高仿id97网站模板,广州安卓程序开发,网络销售平台有哪些,广西响应式网站哪家好一、网络编程套接字
1.1 基础概念
【网络编程】指网络上的主机#xff0c;通过不同的进程#xff0c;以编程的方式实现网络通信#xff1b;当然#xff0c;我们只要满足进程不同就行#xff0c;所以即便是同一个主机#xff0c;只要是不同进程#xff0c;基于网络来传…
一、网络编程套接字
1.1 基础概念
【网络编程】指网络上的主机通过不同的进程以编程的方式实现网络通信当然我们只要满足进程不同就行所以即便是同一个主机只要是不同进程基于网络来传输数据也属于网络编程【套接字】其实是socket的直译套接字就是传输层给应用层提供的网络编程API接口通过这个接口应用层程序可以通过这个接口使用传输层提供的服务而不需要知道它的具体实现
套接字分为两类流式套接字和数据报套接字
流式套接字是基于TCP协议一个传输层协议实现的TCP是一种面向连接型、可靠传输型、面向字节流、全双工的传输层协议流式套接字利用这些特性为应用层提供了一个简单的接口用于发送和接收数据流
数据报套接字是基于UDP协议也是一个传输层协议实现的UDP是一种面向无连接型、不可靠传输型、面向数据报、全双工的传输层协议 1.2 协议特点
接下来讲解以下上述提到的 TCP协议和UDP协议的特点
1面向有连接型 vs 面向无连接型通过网络发送数据分为面向有连接和面向无连接
有连接指在发送数据之前发送端要先和接收端建立一条逻辑意义上的连接连接建好后才能真正发送数据数据发送完毕后要断开连接
就好比打电话在说话之前对方要先同意接听接听并说完话后再挂断电话
无连接则无需考虑建立连接和断开连接发送端可以在任何时候发送数据接收端不知道自己会在何时收到数据所以要时常检查是否收到数据
这个就像发送电子邮件发送端可以随时发送无需让接收端同意接收端则要时常检查是否有收到邮件 2可靠传输 vs 不可靠传输
可靠传输指将要传输的数据尽可能的传输给对方在网络通信的过程中会存在丢包的情况A给B传输10个数据报B收到了9个
原因是A传输给B中间可能会经历很多交换机和路由器这些交换机和路由器不只是转发你的数据要转发很多数据当数据很多时可能会超过它们自身的硬件水平此时多出来的数据无法转发会被直接丢弃掉。
TCP为了对抗丢包内部实现了一些机制重发来实现可靠传输机制后面会详细讲
不可靠传输指再出现丢包后也不负责重发不可靠传输更注重效率在一些注重效率对准确性要求不高的场景使用不可靠传输可靠传输能尽可能保证数据传给接收端但效率上会大打折扣 3面向字节流 vs 面向数据报
面向字节流指传输的数据以字节为单位
面向数据报指传输的数据以数据报为单位传输数据是一个一个数据报一次读写只能读写完整的数据报不能读写半个 4全双工 vs 半双工
全双工指一条链路能够进行双向通信后续代码创建socket对象既可以读(接收)也可以写(发送)
半双工指一条链路只能进行单向通信 二、UDP-数据报套接字编程
socket API 是由传输层给应用层提供的API传输层是封装于操作系统内核态的由操作系统内核直接管理所以可以理解为socket api是由操作系统内核管理的而Java对于系统这些API进行了封装所以使得用户程序可以直接使用这些API
UDP的socket API 有两个重要的类
2.1 DatagramSocket
属于UDP Socket创建DatagramSocket的对象就可以发送和接收UDP数据报先来看构造方法
构造方法描述DatagramSocket( )创建一个UDP数据报套接字的Socket绑定到本机任意一个随机端口DatagramSocket( int port )创建一个UDP数据报套接字的Socket绑定到本机指定的端口号
普通方法
普通方法描述void receive (DatagramPacket p)接收数据报如果没有接收到该方法就会阻塞等待void send(DatagramPacket p)发送数据报不会阻塞等待直接发送无连接void close( )关闭此数据报套接字
当创建一个套接字时系统会为其分配资源绑定端口号如果用完不关闭则会导致资源持续被占用 2.2 DatagramPacket
表示UDP Socket发送和接收的数据报一个DatagramPacket对象就相当于一个UDP数据报
构造方法描述DatagramPacket (byte[] buf, int length)构造⼀个DatagramPacket以用来接收数据报接收的数据保存在字节数组第⼀个参数buf中接收指定长度第⼆个参数length DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 构造⼀个DatagramPacket以用来发送数据报发送的数据为字节数组第⼀个参数buf中从0到指定⻓ 度第⼆个参数lengthaddress指定⽬的主机的IP 和端⼝号
上述方法可以结合下述代码理解
2.3 模拟回显服务器
回显服务器指客户端发送一个请求给服务端服务端将这个请求原封不动的作为相应返回给客户端这就叫回显请求啥相应就是啥接下来先编写服务器程序
public class UdpEchoServer {public DatagramSocket socket null;public UdpEchoServer(int port) throws SocketException {socket new DatagramSocket(port); //创建 UDP Socket 并绑定一个端口号}}
服务器需要在程序启动的时候把在服务器程序的端口号确定下来客户端发送请求时需要知道服务器的IP地址服务器所在主机的IP、端口号port
服务器要能够接收客户端发送的数据socket receive( )需要向receive传入一个UDP数据报
public class UdpEchoServer {public DatagramSocket socket null;public UdpEchoServer(int port) throws SocketException {socket new DatagramSocket(port);}public void start() throws IOException {//1) 接收请求DatagramPacket requestPacket new DatagramPacket(new byte[4096], 4096);//此时创建好的requestPacket 是一个空的数据包//requestPacket包含两个部分1.报头 2.载荷//字节数组用来存储数据socket.receive(requestPacket); //客户端会send一个数据包, 就会跳转到这里//此时由requestPacket 是一个预留好空间的空数据包// 为了方便在 java 代码中处理 (尤其是后面进行打印) 可以把上述数据报中的二进制数据, 拿出来, 构造成 StringString request new String(requestPacket.getData(), 0, requestPacket.getLength());}}接收来自客户端的请求后经过处理后将响应返回给客户端那么该如何知道应该给哪个客户端返回响应在我们receive接收到的数据包里就包含了这个数据包来自于哪个IP来自于哪个端口号客户端
// 2) 根据请求计算响应
String response this.process(request);
// 3) 把响应写回到客户端
DatagramPacket responsePacket new DatagramPacket(response.getBytes(), 0, response.getBytes().length, requestPacket.getSocketAddress());
socket.send(responsePacket);requestPacket.getSocketAddress() 这个方法返回的对象里就包含了客户端的IP地址和端口号
上述代码干的事情就是将字符串类型的二进制数据再构造会UDP数据包并发送给客户端
服务端完整代码如下
public class UdpEchoServer {private DatagramSocket socket null;public UdpEchoServer(int port) throws SocketException {socket new DatagramSocket(port);}public void start() throws IOException {Scanner scanner new Scanner(System.in);System.out.println(服务器启动!);while (true) { // 服务器需要7*24小时持续接收并处理请求// 1) 读取请求并解析DatagramPacket requestPacket new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);//receive方法中的requestPacket是一个空的数据包客户端程序通过send方法发送有数据的数据包后//会直接跳转到这里的receive方法而这里的requestPacket是一个预留好空间的空数据包// 为了方便在 java 代码中处理 (尤其是后面进行打印) 可以把上述数据报中的二进制数据, 拿出来, 构造成 StringString request new String(requestPacket.getData(), 0, requestPacket.getLength());//将字节数组构造成String类的对象// 2) 根据请求计算响应String response this.process(request);// 3) 把响应写回到客户端DatagramPacket responsePacket new DatagramPacket(response.getBytes(), 0, response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);System.out.printf([%s:%d] req%s, resp%s\n, requestPacket.getAddress(), requestPacket.getPort(),request, response); // 从左到右依次为: IP地址端口号请求响应}}// 由于当前写的是 回显服务器public String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server new UdpEchoServer(9090);server.start();}
} 接下来写客户端代码
首先客户端需要知道服务器的IP和端口号端口号是我们之前就设置的9090IP用127.0.0.1当服务器和客户端在一个主机上就用环回IP这是系统提供的特殊的IP
public class UdpEchoClient {private DatagramSocket socket null;private String serverIp;private int serverPort;public UdpEchoClient(String serverIp, int serverPort) throws SocketException {socket new DatagramSocket();// 这俩信息需要额外记录下来, 以备后续使用.this.serverIp serverIp;this.serverPort serverPort;}
}
上述构造socket对象没有指定端口号这样操作系统会分配一个空闲的端口号这个端口号每次重新启动程序都不一样
// 1. 从控制台读取用户输入
String request scanner.next();
// 2. 构造请求并发送
// 构造请求数据报的时候, 不光要有数据, 还要有 目标
DatagramPacket requestPacket new DatagramPacket(request.getBytes(), 0, request.getBytes().length, InetAddress.getByName(serverIp), serverPort);
socket.send(requestPacket); //发送数据包
上述InetAddress.getByName(serverIp)是将字符串格式的IP地址转成Java能识别的InetAddress对象
发送完数据包服务器经过处理返回响应客户端就要接收响应
// 3. 读取响应数据
//构造一个空的数据包负责接收服务器返回的响应
DatagramPacket responsePacket new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);
// 4. 显示响应到控制台上.
String response new String(responsePacket.getData(), 0, responsePacket.getLength());
System.out.println(response);
在第2步执行完send后客户端程序紧接着到第三步的receive由于从发送请求到返回响应需要些时间所以这里receive会阻塞阻塞到接收到服务器返回响应
完整的客户端代码如下
public class UdpEchoClient {private DatagramSocket socket null;private String serverIp;private int serverPort;public UdpEchoClient(String serverIp, int serverPort) throws SocketException {socket new DatagramSocket();// 这俩信息需要额外记录下来, 以备后续使用.this.serverIp serverIp;this.serverPort serverPort;}public void start() throws IOException {System.out.println(客户端启动!);Scanner scanner new Scanner(System.in);while (true) {System.out.print(请输入要发送的请求: );// 1. 从控制台读取用户输入String request scanner.next();// 2. 构造请求并发送// 构造请求数据报的时候, 不光要有数据, 还要有 目标DatagramPacket requestPacket new DatagramPacket(request.getBytes(), 0, request.getBytes().length,InetAddress.getByName(serverIp), serverPort);socket.send(requestPacket);// 3. 读取响应数据DatagramPacket responsePacket new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);// 4. 显示响应到控制台上.String response new String(responsePacket.getData(), 0, responsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {UdpEchoClient client new UdpEchoClient(127.0.0.1, 9090);// UdpEchoClient client new UdpEchoClient(139.155.74.81, 9090);client.start();}
}
接下来启动服务器程序和客户端程序
客户端可以不断发送请求并得到响应 服务端会不断处理客户端的请求