Socket编程:客户端与服务器通信全解析(网络编程)
发布时间:2026/8/14 15:36:54 作者:尧图编辑部 阅读量:1,286
)
客⼾端和服务端服务端在常⻅的⽹络数据传输场景下把提供服务的⼀⽅进程称为服务端可以提供对外服务。客⼾端获取服务的⼀⽅进程称为客⼾端。Socket套接字概念Socket套接字是由系统提供⽤于⽹络通信的技术是基于TCP/IP协议的⽹络通信的基本操作单元。基于Socket套接字的⽹络程序开发就是⽹络编程。socket 是操作系统中特殊的文件,表示网卡硬件设备socket api 传输层,提供给应用层TCP : 有链接, 可靠传输, 面向字节流, 全双工UDP : 无链接, 不可靠传输, 面向数据报, 全双工链接:抽象的,虚拟的链接.通信双方,各自保存对方的关键信息(IP和端口)TCP有链接,先保存对方的关键信息,然后发送数据UDP无链接,不需要保存对方的关键信息,直接发送数据不可靠传输:数据发送出去之后,关系对方是否收到,如果可靠传输:发送出去之后,不管了全双工:同时进行双向通信半双工:同一时刻,只能单向通信(兽医)UDP数据报套接字编程DatagramSocketDatagram:数据报创建一个这样的对象,就相当于在系统内核里创建了一个socket文件. 创建socket文件,也会占用文件描述符表的一个位置,用完之后要记得及时关闭,否则可能会出现文件资源泄露DatagramSocket 构造方法DatagramSocket()创建⼀个UDP数据报套接字的Socket绑定到本机任意⼀个随机端⼝⼀般⽤于客⼾端DatagramSocket(int port)创建⼀个UDP数据报套接字的Socket绑定到本机指定的端⼝⼀般⽤于服务端谁主动,谁就是客户端. 谁被动,谁就是服务器.DatagramSocket 方法void receive(DatagramPacket p)从此套接字接收数据报如果没有接收到数据报该⽅法会阻塞等待void send(DatagramPacket p)从此套接字发送数据报包不会阻塞等待直接发送void close()关闭此数据报套接字DatagramPacketDatagramPacket 构造方法DatagramPacket(byte[] buf, int length)构造⼀个DatagramPacket以⽤来接收数据报,接收的数据保存在字节数组第⼀个参数buf中接收指定 ⻓度第⼆个参数lengthDatagramPacket(byte[] buf, int offset, int length, SocketAddress address)构造⼀个DatagramPacket以⽤来发送数据报,发送的数据为字节数组第⼀个参数buf中从0到指定⻓度第⼆个参数length。address指定⽬的主机的IP和端⼝号DatagramPacket ⽅法InetAddress getAddress()从接收的数据报中获取发送端主机IP地址或从发送的数据报中获取接收端主机IP地址int getPort()从接收的数据报中获取发送端主机的端⼝号或从发送的数据报中获取接收端主机端⼝号byte[] getData()获取数据报中的数据InetSocketAddress:创建⼀个Socket地址包含IP地址和端⼝号代码示例import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class UdpEchoServer { //先创建 socket对象 private DatagramSocket socket null; public UdpEchoServer(int port) throws SocketException { socket new DatagramSocket(port); } public void start() throws IOException { //启动服务器 System.out.println(服务器启动....); //服务器,需要不断处理客户发送过来的请求 while(true){ //循环一次就是处理一个请求 //1.读取请求并解析 DatagramPacket requestPacket new DatagramPacket(new byte[1024],1024); socket.receive(requestPacket); //为了处理方便 String request new String(requestPacket.getData(),0,requestPacket.getLength()); //2.根据请求构造响应 String response process(request); //3.把响应返回给客户端 DatagramPacket responsePacket new DatagramPacket(response.getBytes(),response.getBytes().length, requestPacket.getSocketAddress()); socket.send(responsePacket); System.out.printf([%s:%d]; resp: %s\n,requestPacket.getAddress().toString(),responsePacket.getPort(),request,response); } } private String process(String request) { return request; } public static void main(String[] args) throws IOException { //端口号是一个整数,随意指定 UdpEchoServer udpEchoServer new UdpEchoServer(9090); udpEchoServer.start(); } }import java.io.IOException; import java.net.*; import java.util.Scanner; public class UdpEchoCient { private DatagramSocket socket null; private String serverIP; private int serverPort; public UdpEchoCient(String serverIp,int serverPort) throws SocketException { socket new DatagramSocket(); this.serverIP serverIp; this.serverPort serverPort; } public void start() throws IOException { System.out.println(客户端启动); Scanner sc new Scanner(System.in); while (true) { //1.从控制台读取用户输入 System.out.println(- ); String request sc.next(); //2.构造请求,发送给服务器 DatagramPacket requestPacket new DatagramPacket(request.getBytes(), request.getBytes().length, InetAddress.getByName(serverIP), this.serverPort); socket.send(requestPacket); //3.读取服务器响应 DatagramPacket responsePacket new DatagramPacket(new byte[1024], 1024); socket.receive(responsePacket); String response new String(requestPacket.getData(), 0, requestPacket.getLength()); System.out.println(response); } } public static void main(String[] args) throws IOException { UdpEchoCient cient new UdpEchoCient(127.0.0.1,9090); cient.start(); } }服务器必须要指定固定的端口,确保客户端随时能找到服务器.客户端来说,必须不指定固定端口,让系统随机分配空闲的端口,避免端口号冲突(大饼)