Java中使⽤TCP协议通信,使用ServerSocket来建立链接,使用Socket进行通信.
ServerSocket
ServerSocket是创建TCP服务端Socket的api,主要方法:
| 方法签名 | 说明 |
| ServerSocket(int port) | 创建一个服务端流套接字Socket,并绑定指定端口 |
| Socket accpet() | 开始监听指定端口,有客户端链接后,返回一个服务端Socket对象,基于这个对象与客户端Socket对象通信,如果没有客户端链接,则阻塞等待, |
| void close() | 关闭套接字 |
Socket
socket是客户端socket或服务端接收到客户端建立链接的请求后,返回的服务端socket.不管是客户端Socket还是服务端Socket,都是双方建立链接后,保存对端信息并用来通信的.Socket的主要方法:
| 方法签名 | 说明 |
| Socket(String host,int port) | 创建⼀个客⼾端流套接字Socket,并与对应IP的主机上,对应端⼝的进程建⽴连接. |
| InetAddress getInetAddress() | 返回套接字所链接的地址 |
| InputStream getInputStream() | 返回套接字的输入流 |
| OutputStream getOutputStream() | 返回套接字的输出流 |
输入流InputStream与输出流OutputStream分别使用Scanner与PrintWrite进行封装,方便请求与响应的传输.
建立一个简单的回显服务器
Server
服务端负责接收客户端发送来的数据,然后处理相应逻辑,返回给客户端一个响应.
public class TCPEchoServer {
ServerSocket serverSocket = null;
public TCPEchoServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服务器已启动!");
//使用线程池来管理线程
ExecutorService pool = Executors.newCachedThreadPool();
//接受客户端链接
while (true){
Socket clientSocket = serverSocket.accept();
pool.submit(new Runnable() {
@Override
public void run() {
try {
processConnection(clientSocket);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
}
}
private void processConnection(Socket clientSocket) throws IOException {
System.out.printf("[%s:%d]已上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());
//获取socket中的输入流和输出流
try(InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream()){
//扫描客户端请求
while (true) {
//用Scanner包装inputStream输入流 方便获取请求
Scanner scanner = new Scanner(inputStream);
if(!scanner.hasNext()){
//用户不再输入时 跳出循环 当用户断开后也为不再输入
System.out.printf("[%s:%d]已下线!\n",clientSocket.getInetAddress(),clientSocket.getPort());
break;
}
String request = scanner.next();
//计算响应
String response = process(request);
//直接使用outputStream的write方法无法返回换行符"\n",导致客户端处理较为困难
//选择使用PrintWriter包装outputStream,使用PrintWriter的println方法
PrintWriter writer = new PrintWriter(outputStream);
writer.println(response);
//PrintWriter中存在缓冲区,需要"攒够一波"数据之后才会真正的发送数据
//使用flush方法,冲刷缓冲器,让缓冲区的内容直接发送出去
writer.flush();
//打印服务器日志
System.out.printf("[%s:%d] req: %s,resp : %s\n",clientSocket.getInetAddress(),
clientSocket.getPort(),request,response);
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
//执行完毕这一次的链接后 关闭链接
clientSocket.close();
}
}
private String process(String request) {
return "响应:"+request;
}
public static void main(String[] args) throws IOException {
TCPEchoServer server = new TCPEchoServer(8848);
server.start();
}
}
Client
客户端负责向服务端发送请求,并等待接收服务端的响应.
public class TCPEchoClient {
private Socket socket = null;
public TCPEchoClient(String ip,int port) throws IOException {
//new操作完成后 开始建立链接 等待服务端accept
socket = new Socket(ip, port);
}
public void start(){
System.out.println("客户端已启动");
//接收用户输入的请求
Scanner input = new Scanner(System.in);
try(InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();){
//不断扫描
while(true){
System.out.print("->");
if(!input.hasNext()){
break;
}
//获取请求
String request = input.next();
PrintWriter writer = new PrintWriter(outputStream);
writer.println(request);
writer.flush();
//接收服务端响应
Scanner netWork = new Scanner(inputStream);
String response = netWork.next();
//向用户展示响应
System.out.println(response);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws IOException {
TCPEchoClient client = new TCPEchoClient("127.0.0.1",8848);
client.start();
}
}
运行结果:
启动客户端与服务端,从客户端发送请求,查看客户端与服务端的表现.



438

被折叠的 条评论
为什么被折叠?



