目录
一、引言
二、网络编程基本概念
2.1 什么是网络编程?
2.2 基本知识
三、Socket套接字
3.1 概念
3.2 分类
1.流套接字:使用传输层TCP协议
2. 数据报套接字:使用传输层UDP协议
3.原始套接字:用于自定义传输层协议
四、UDP数据报套接字编程
一、API介绍
五、TCP流套接字编程
六、服务器引入多线程
七、服务器引入线程池
一、引言
本篇文章将继续讨论网络编程的知识,重点介绍网络编程的基本概念,以及Socket套接字的相关信息。
二、网络编程基本概念
2.1 什么是网络编程?
网络编程指网络上的主机,通过不同的进程,以编程的方式实现网络通信。此处,我们只需要保证不同的进程即可,即使是同一台主机上的不同进程也能进行网络编程。
2.2 基本知识
发送端:数据的发送方进程,就是发送端。网络通信中的源主机。
接收端:数据的接收方进程,就是接收端。网络通信中的目的主机。
收发端:发送端和接收端两端,就称为收发端。
请求与响应:请求,即对对方发送一个自己的需求。响应:即对对方的请求提供一个回答。
服务端:提供服务的一方进程称为服务端,可以提供对外服务。
客户端:获取服务的一方进程,称为客户端。
常见的客户端与服务端模型:
1. 客户端先发送请求到服务器。
2.服务器根据请求数据,执行相应的业务处理。
3.服务器返回响应,发送业务处理结果。
4.客户端根据处理结果,展示处理结果。
三、Socket套接字
3.1 概念
Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络通信。
3.2 分类
1.流套接字:使用传输层TCP协议
对于字节流来说,传输数据是基于IO流,流式数据的特征就是在IO流没有关闭的情况下,是无边界的数据,可以多次发送,也可以分开多次接收。
2. 数据报套接字:使用传输层UDP协议
传输的数据是一块一块的,发送一块数据假如100个字节,必须一次发送,接收也必须一次接收100个字节,而不能分成100次,每次接收一个字节。
3.原始套接字:用于自定义传输层协议
原始层套接字用于自定义传输层协议,用于读写内核没有处理的IP协议数据。这个套接字简单了解即可。
Java流套接字通信模型:
Socket编程注意事项:
1. 客户端和服务端:开发时,经常是基于一个主机开启两个进程作为客户端和服务器,但真实场景是不同的主机
2. 注意目的IP和目的端口号,标识了一次数据传输时要发送数据的终点主机和进程
3. Socket编程我们是使用流套接字和数据报套接字,基于传输层的TCP或UDP协议,但应用层协议也需要考虑。
4. 如果一个进程A已经绑定了一个端口,再启动一个进程B绑定该端口,就会报错,这种情况也叫端口被占用。对于Java进程来说,端口被占用的错误信息一般会报:Address already in use。此时我们就需要进行检查,看看哪个进程绑定了这个端口。通过任务管理器中的PID进行查看。
四、UDP数据报套接字编程
一、API介绍
DatagramSocket构造方法:
用于发送和接收UDP数据报:绑定到本机一个随机端口,若添加参数(int port)就可以绑定到指定端口。
DatagramSocket方法:
方法签名 | 方法说明 |
void receive(DatagramPacket p) | 从此套接字接收数据报(会阻塞等待) |
void send(DatagramPacket p) | 从此套接字发送数据报包(不会阻塞等待) |
void close() | 关闭此数据报套接字 |
DatagramPacket是UDP Socket发送和接收的数据报。
DatagramPacket构造方法:
方法签名 | 方法说明 |
DatagramPacket(byte[] buf,int length) | 构造一个DatagramPacket用来接收数据报,接收的数据保存在字节数组中(buf)中,接收指定的长度(length) |
DatagramPacket(byte[] buf,int offset,int length,SocketAddress address) | 构造一个DatagramPacket用来接收数据报,接收的数据保存在buf中,从offset开始,进行length字节,address指定目的主机和IP |
DatagramPacket方法:
方法签名 | 方法说明 |
inetAddress getAddress() | 从接收的数据报中,获取发送端主机IP,或从发送的数据报中获取接收端主机IP |
int getPort() | 从接收的数据报中,获取发送端主机的端口号,或从发送的数据报中,获取接收端主机端口号 |
byte[] getData() | 获取数据报中的数据 |
构造UDP发送的数据报时,需要传入SocketAddress,该对象可以使用InetSocketAddress来创建。
InetDSocketAddress构造方法:
方法签名 | 方法说明 |
InetSocketAddress(InetAddress addr,int port) | 创建一个Socket地址,包含IP地址和端口号 |
代码实例:
private DatagramSocket socket = null;
public UdpEchoServer(int port) throws SocketException {
socket = new DatagramSocket(port);
}
public void start() throws IOException {
System.out.println("服务器启动!");
while (true){
DatagramPacket requestPacket = new DatagramPacket(new byte[4096],40);
socket.receive(requestPacket);
// 转为字符串
String request = new String(requestPacket.getData(),0,requestPacket.getLength());
// 计算响应
String response = process(request);
// 把响应写回给客户端
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),requestPacket.getLength(),requestPacket.getSocketAddress());
socket.send(responsePacket);
}
}
public String process(String request){
return request;
}
public static void main(String[] args) throws IOException {
UdpEchoServer echo = new UdpEchoServer(9090);
echo.start();
}
五、TCP流套接字编程
ServerSocket
创建一个服务端流套接字Socket,并绑定到指定端口
Socket accept():
void close()
Socket是客户端Socket,或服务端中接收到客⼾端建立连接(accept方法)的请求后,返回的服
六、服务器引入多线程
代码:
public class start {
public static void main(String[] args) {
System.out.println("服务器启动!");
while (true){
Socket clientSocket = serverSocket.accept();
Thread t = new Thread(() ->{
processConnection(clientSocket);
});
t.start();
}
}
}
七、服务器引入线程池
代码:
public void start(){
System.out.println("服务器启动!");
ExecutorService service = Executors.newCachedThreadPool();
while (true){
Socket clientSocket = serverPocket.accept();
service.submit(new Runnable() {
@Override
public void run() {
processConnection(clientSocket);
}
});
}
}
八、总结
本篇文章简单介绍了一下Socket套接字中UDP协议和TCP协议的运用,感谢大家观看!