Socket编程:客户端与服务器通信全解析(网络编程)

客⼾端和服务端

服务端:在常⻅的⽹络数据传输场景下,把提供服务的⼀⽅进程,称为服务端,可以提供对外服务。

客⼾端:获取服务的⼀⽅进程,称为客⼾端。

Socket套接字

概念

Socket套接字,是由系统提供⽤于⽹络通信的技术,是基于TCP/IP协议的⽹络通信的基本操作单元。基于Socket套接字的⽹络程序开发就是⽹络编程。

socket 是操作系统中特殊的文件,表示"网卡"硬件设备

socket api 传输层,提供给应用层

TCP : 有链接, 可靠传输, 面向字节流, 全双工

UDP : 无链接, 不可靠传输, 面向数据报, 全双工

**链接:**抽象的,虚拟的链接.通信双方,各自保存对方的关键信息(IP和端口)

TCP 有链接,先保存对方的关键信息,然后发送数据

UDP 无链接,不需要保存对方的关键信息,直接发送数据

**不可靠传输:**数据发送出去之后,关系对方是否收到,如果

**可靠传输:**发送出去之后,不管了

**全双工:**同时进行双向通信

半双工: 同一时刻,只能单向通信**(兽医)**

UDP数据报套接字编程

DatagramSocket

Datagram:数据报

创建一个这样的对象,就相当于在系统内核里创建了一个socket文件 . 创建socket文件,也会占用文件描述符表的一个位置,用完之后要记得及时关闭,否则可能会出现**"文件资源泄露"**

DatagramSocket 构造方法

|--------------------------|----------------------------------------------|
| DatagramSocket() | 创建⼀个UDP数据报套接字的Socket,绑定到本机任 意⼀个随机端⼝(⼀般⽤于客⼾端) |
| DatagramSocket(int port) | 创建⼀个UDP数据报套接字的Socket,绑定到本机指 定的端⼝(⼀般⽤于服务端) |

谁主动,谁就是客户端. 谁被动,谁就是服务器.

DatagramSocket 方法

|--------------------------------|--------------------------------------|
| void receive(DatagramPacket p) | 从此套接字接收数据报(如果没有接收到数据报,该 ⽅法会阻塞等待) |
| void send(DatagramPacket p) | 从此套接字发送数据报包(不会阻塞等待,直接发 送) |
| void close() | 关闭此数据报套接字 |

DatagramPacket

DatagramPacket 构造方法

|-----------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
| DatagramPacket(byte\[\] buf, int length) | 构造⼀个DatagramPacket以⽤来接收数据报,接收的 数据保存在字节数组(第⼀个参数buf)中,接收指定 ⻓度(第⼆个参数length) |
| DatagramPacket(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地址和端⼝号

代码示例

java 复制代码
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();
    }
}
java 复制代码
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();
    }
}

**服务器必须要指定固定的端口,**确保客户端随时能找到服务器.

客户端来说,必须不指定固定端口 ,让系统随机分配空闲的端口,避免端口号冲突**(大饼)**

相关推荐
凤舞飘伶几秒前
服务器内存满日常运维命令
linux·运维·服务器
西柚小萌新2 分钟前
【论文阅读】--AgentPoison:通过投毒记忆库或知识库对LLM智能体进行红队测试
网络·安全
Fcy64836 分钟前
Linux下 Socket编程 —— TCP网络编程
linux·网络·tcp/ip
IPdodo_1 小时前
静态 IP 访问异常排查:403/429 归因与迁移验收
服务器·网络·数据库·python·网络协议·php·性能测试
ouynagda1 小时前
HTTP协议与Socket网络编程笔记
网络·笔记·http
haerapi1 小时前
流式对话接口怎么选:SSE 与 WebSocket 的原理、实现和工程边界
网络·websocket·网络协议
砚凝霜2 小时前
【软考信息安全】第二章 网络攻击基础与常见技术方法
网络·安全·php
Raas1002 小时前
AI网关在架构中的位置?MAI Gateway(魔芋企业级AI网关)给出企业级答案
大数据·网络·人工智能·架构·gateway·ai网关·mai gateway
hflmwl82 小时前
Motrix电脑版官网免费下载,motrix服务器绿色版官方下载安装
运维·服务器·motrix
2401_868534782 小时前
安全管理策略和制度
网络·安全