基于Tcp的简单服务器
- UDP协议无连接类似于发微信
- TCP协议有链接类似于打电话
- 所以基于TCP的服务器先要到内核中获取一个TCP连接,UDP不需要获取连接
- TCP的连接管理是由操作系统的内核来管理的,客户端和服务器建立连接的过程中,完全由内核来进行负责。负责程序的代码感知不到
- TCP的来连接管理需要先描述在组织
- 描述:通信的五元组
- 组织:使用一个阻塞队列来组织若干个连接对象
- 代码中调用这个accept方法就是从阻塞队列当中获取一个链接对象(在应用程序中的化身就是Socket对象)
- 后续数据读写都是根据这个clientSocket这个对象来进行展开的
- 如果都服务器启动之后,没有客户端建立连接,此时代码中调用accpt方法就会阻塞,阻塞到真的有客户端建立连接为止。
- 简单的TCP服务器
package com.zb.network.test;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpEchoServer {
private ServerSocket serverSocket = null;
public TcpEchoServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服务器启动");
while (true) {
Socket clientSocket = serverSocket.accept();
processConnection(clientSocket);
}
}
private void processConnection(Socket clientSocket) {
System.out.printf("[%s:%d]客户端上线\n", clientSocket.getInetAddress().toString(),
clientSocket.getPort());
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()))){
while (true) {
String request = bufferedReader.readLine();
String response = process(request);
bufferedWriter.write(response + "\n");
bufferedWriter.flush();
System.out.printf("[%s:%d] req: %s; resp: %s\n", clientSocket.getInetAddress().toString(),
clientSocket.getPort(), request, response);
}
} catch (IOException e) {
System.out.printf("[%s:%d]客户端下线\n", clientSocket.getInetAddress().toString(),
clientSocket.getPort());
}
}
private String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
TcpEchoServer server = new TcpEchoServer(9090);
server.start();
}
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/7e92255546805e067c4b46ad479c12b8.png)
package com.zb.network.test;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class TcpEchoClient {
private Socket socket = null;
public TcpEchoClient(String serverIp, int serverPort) throws IOException {
socket = new Socket(serverIp,serverPort);
}
public void start(){
System.out.println("客户端启动");
Scanner sc = new Scanner(System.in);
try(
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {
while (true){
System.out.print("->");
String request = sc.nextLine();
if ("exit".equals(request)){
break;
}
bufferedWriter.write(request + "\n");
bufferedWriter.flush();
String response = bufferedReader.readLine();
System.out.println(response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
TcpEchoClient client = new TcpEchoClient("127.0.0.1",9090);
client.start();
}
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/7c6ff054b0bf188b0a3a0f3fedab8901.png)
注意
解决Tcp连接只能有一个客户端连接服务器的问题
- 原因就是accept方法的调用,调用几个accept方法就处理几个连接,在代码中出现的问题就是由于为了要实现长连接,导致循环退不出去,导致accept方法无法正常调用,所以只能有一个客户端和服务器进行连接
- 解决方法就是使用多线程,用一个线程专门来调用accept方法从而实现并发操作,这样既可以实现长连接又可以正常调用accept方法,其实单线程的方式也可以解决,使用IO多路复用即可,而且十分高效,但是比较麻烦
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5ef9118bc7cd03f89182fc6bece7d148.png)
- 这样就可以让多个客户端同时连接服务器