什么是网络编程
是一种面向连接的、可靠的、基于字节流的传输层通信协议。它旨在适应支持多网络应用的分层协议层次结构,并在不可靠的互联网络上提供可靠的端到端字节流。TCP协议由IETF的RFC 793定义,是OSI层中的传输层协议,用于在远程计算机之间创建连接,并通过传输和确保通过支持网络和Internet传递消息来确保数据的传递。
三次握手:
- 第一次握手:客户端向服务端发送一个SYN包(同步报文),并进入SYN_SENT状态,等待服务器确认。
- 第二次握手:服务端收到SYN包后,会确认客户端的SYN(ACK=1,ack=x+1),同时自己也发送一个SYN包(SYN=1,seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态。
- 第三次握手:客户端收到服务端的SYN+ACK包,向服务器发送确认包(ACK=1,ack=y+1,seq=x+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。
四次挥手:
- 第一次挥手:客户端数据发送完毕,向服务端发送终止报文请求释放连接。
- 第二次挥手:服务端收到连接释放报文,如果服务端此时还有未发送完的数据,则先标记ACK=1,ack=u+1,然后发送自己的数据,待发送完毕后,再发送FIN报文,进入LAST-ACK状态。
- 第三次挥手:当服务端数据发送完毕,向客户端发送终止报文,发送连接释放请求,进入LAST-ACK状态。
- 第四次挥手:客户端收到连接释放请求,向服务器端发送确认报文,此时客户端进入TIME-WAIT状态,会等待 2MSL(最长报文段寿命),若期间没有收到服务器端的数据报文,进入CLOSED状态。服务器端收到客户端的确认报文后,也进入CLOSED状态。
下面我以一个TCP协议编程进行演示
TCP编程
编写一个TCP协议的编程示例,通常涉及两个主要部分:客户端(Client)和服务器(Server)。
当使用Java语言编写TCP协议的客户端和服务器时,可以使用java.net.Socket和java.net.ServerSocket类。以下是一个简单的示例:
服务器(Server)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) {
int port = 12345;
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("服务器已启动,等待客户端连接...");
// 监听客户端连接
Socket clientSocket = serverSocket.accept();
System.out.println("客户端已连接:" + clientSocket.getRemoteSocketAddress());
// 读取客户端数据
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println("收到来自客户端的消息:" + inputLine);
// 发送响应给客户端
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
out.println("服务器已收到消息");
// 假设处理完一条消息后结束连接
break;
}
// 关闭资源
in.close();
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端(Client)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPClient {
public static void main(String[] args) {
String hostname = "HJW"; // 或者服务器的IP地址
int port = 12345;
try (Socket socket = new Socket(hostname, port)) {
System.out.println("连接到服务器:" + socket.getRemoteSocketAddress());
// 发送数据给服务器
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println("你好,服务器!");
// 读取服务器响应
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println("收到来自服务器的消息:" + inputLine);
// 假设读取完一条消息后结束连接
break;
}
// 关闭资源
in.close();
} catch (UnknownHostException e) {
System.err.println("无法识别主机:" + hostname);
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意:
在这个示例中,服务器和客户端使用try-with-resources语句来自动关闭Socket和其他资源。这是一种在Java 7及更高版本中推荐的资源管理方式。
BufferedReader和PrintWriter用于简化文本数据的读写。如果你需要处理二进制数据,你可以使用InputStream和OutputStream。
在实际应用中,你可能需要实现更复杂的错误处理、连接管理、数据编码/解码等功能。
在这个示例中,服务器和客户端在发送和接收完一条消息后就关闭了连接。在实际应用中,你可能需要实现更复杂的会话管理逻辑。