文章目录
- TCP流套接字编程
- ServerSocket API
- Socket API
- 案例一
TCP流套接字编程
ServerSocket API
ServerSocket 是创建TCP服务端Socket的API。
ServerSocket 构造方法
方法签名 | 方法说明 |
---|---|
ServerSocket(int port) | 创建一个服务端流套接字Socket,并绑定到指定端口 |
ServerSocket 方法:
方法签名 | 方法说明 |
---|---|
Socket accept() | 开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待 |
void close() | 关闭此套接字 |
Socket API
Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。
Socket 构造方法:
方法签名 | 方法说明 |
---|---|
Socket(String host, int port) | 创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接 |
Socket 方法:
方法签名 | 方法说明 |
---|---|
InetAddress getInetAddress() | 返回套接字所连接的地址 |
InputStream getInputStream() | 返回此套接字的输入流 |
OutputStream getOutputStream() | 返回此套接字的输出流 |
案例一
回显服务
通过简单的回显服务,了解TCP网络编程的全部过程
此处构造socket并且实例化
接下来构造启动服务器程序方法.因为Tcp和Udp并不一样,Tcp是要先建立连接,所以需要先建立连接,然后对接收到的数据进行处理
执行到processConnection方法,就说明此时服务器和客户端已经建立连接,可以进行一些数据处理的操作了
TcpEchoServer服务端
public class TcpEchoServer {
private ServerSocket listenSocket = null;
public TcpEchoServer(int port) throws IOException {
listenSocket = new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服务器启动!");
while(true){
//建立连接
Socket socket = listenSocket.accept();
processConnection(socket);
}
}
private void processConnection(Socket clientSocket) {
System.out.printf("[%s:%d]建立连接\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
try(InputStream inputStream = clientSocket.getInputStream()) {
try (OutputStream outputStream = clientSocket.getOutputStream()){
Scanner scanner = new Scanner(inputStream);
while (true) {
if(!scanner.hasNext()){
System.out.printf("[%s:%d]断开连接\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
break;
}
String request = scanner.next();
String response = process(request);
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println(response);
// 刷新缓冲区, 如果没有这个刷新, 可能客户端就不能第一时间看到响应结果.
printWriter.flush();
System.out.printf("[%s:%d] req: %s, resp: %s\n", clientSocket.getInetAddress().toString(),
clientSocket.getPort(), request, response);
}
}
}catch (IOException e) {
e.printStackTrace();
}finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
TcpEchoServer server = new TcpEchoServer(9090);
server.start();
}
}
客户端代码写完以后,就需要实现客户端的代码
构造方法中的IP地址和端口号是要建立连接的服务器的ip地址和端口号
使用两个try() 和InputStream,OutputStream 用接受和发送客户端的数据流给服务器
操作步骤一
从控制台获取到要用户输入的字符串并且发送给服务器
操作步骤二
从服务器获取响应,并且将结果显示在控制台上
TcpEchoclient客户端
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 scanner = new Scanner(System.in);
try (InputStream inputStream = socket.getInputStream()){
try (OutputStream outputStream = socket.getOutputStream()){
while (true) {
System.out.print("->");
String request = scanner.next();
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println(request);
printWriter.flush();
Scanner respScanner = new Scanner(inputStream);
String response = respScanner.next();
System.out.printf("req: %s, resp: %s\n", request, 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();
}
}
上述的代码,一个服务器只能接收一个客户端的请求.一个服务器不应该只可以处理一个客户端,所以我们需要对代码进行改进.实现多线程
能够和客户端进行交互的前提就是要先调用accept,接收连接,
原因就是第二次连接的时候,第一次的accept并没有断开连接,所以客户端和服务器并不是再次进行连接,也就无法实现多线程
为服务器加入多线程.
方法一:
每次连接连接之后,就进入一个线程,这样就可以实现多线程
方法二:使用线程池: