UDP客户端和服务端

IP地址(源IP,目的IP)
用来识别互联网上一台主机的位置

端口号(源端口,目的端口)
用来区分一台主机上的哪个应用程序
(占两个字节的整数)

五元组:
源IP,
目的IP
源端口,
目的端口
协议类型

通过一个五元组表示一个唯一的通信

Socket API本质是一个文件,网卡的抽象
Java标准库中提供了两种风格:
1.UDP DatagramSocket:面向数据报(发送接收数据,必须以一定的数据包为单位进行传输)
2.TCP ServerSocket:面向字节流

这两个是传输层中最重要的两个协议。

UDP服务器

现在以回显服务器为例(echo server)

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpEchoServer {
    //对于一个服务器,核心流程为两步
    //1.初始化操作(实例化Socket对象)
    //2.进入主循环,接受并处理请求
    //读取数据并解析
    //根据请求计算响应
    //吧响应结果返回到客户端
    private DatagramSocket socket = null;
    //绑定端口号
    //构造Socket时如果没写IP,默认是0.0.0.0(特殊IP)会关联到这个主机的所有网卡IP
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动");
        while (true) {
            //UDP socket发送接受数据的基本单位
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            //当客户端没发任何数据,receive就会阻塞
            socket.receive(requestPacket);
            //当有客户端数据过来了,receive就会把数据放到DatagramPacket对象的缓冲区
            //吧数据转成String
            //用户实际发送的数据可能远小于4096,而此处得到的长度就是4096,
            //可以通过trim就可以去掉不必要的空白字符
            String request = new String(requestPacket.getData(),
                    0,requestPacket.getLength()).trim();
            String response = process(request);
            //requestPacket.getSocketAddress()就是客户端的地址和端口
            //response.getBytes().length得到的是字节数
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
                    response.getBytes().length,requestPacket.getSocketAddress());
            socket.send(requestPacket);
            System.out.printf("[%s:%d] req: %s;resp:%s\n",requestPacket.getAddress().toString(),
                    requestPacket.getPort(),request,response);
        }
    }

    public String process(String request) {
        //此处是回显服务器,请求啥响应内容就是啥
        //如果是更复杂的服务器,此处就包含很多业务逻辑
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer server = new UdpEchoServer(9090);
        server.start();
    }
}
import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpEchoClient {
    //客户端分四步
    //1.从用户这里读取数据
    //2.构造请求发给服务器
    //3.从服务器读取响应
    //4.吧响应写回给客户端
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverPort;
    //需要在启动客户端是来指定需要连接那个服务器
    public UdpEchoClient(String serverIp,int serverPort) throws SocketException {
        this.serverIp = serverIp;
        this.serverPort = serverPort;
        //不需要绑定端口号,由操作系统自动分配一个空闲端口
        //一个端口号通常只能被一个进程绑定
        //服务器绑定了端口之后,客户端才能访问
        //客户端如果绑定端口,一个主机只能启动一个客户端(通常不允许)
        socket = new DatagramSocket();
    }
    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.print("->");
            String request = scanner.nextLine();
            if (request.equals("exit")) {
                break;
            }
            //构造请求
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
                    request.getBytes().length, InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            String response = new String(requestPacket.getData(),0,requestPacket.getLength()).trim();
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException {
        //这里的IP是特殊IP,环回IP,由于这里服务器和客户端在同一主机
        //如果不在同一主机,要写成服务器IP
        UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);
        client.start();
    }
}

在这里插入图片描述
在这里插入图片描述
客户端服务器是为了跨主机通信
要把服务器部署到云服务器上
部署主要是两个步骤:

1.把代码打成jar包
2.把jar包拷贝到服务器上运行

用idea打jar包:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

现在写一个翻译服务器来体会服务器里面process的业务逻辑,一般比较复杂的服务器,process里面的代码往往很复杂。

import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

public class UdpDictServer extends UdpEchoServer {
    private Map<String,String> dict = new HashMap<>();
    public UdpDictServer(int port) throws SocketException {
        super(port);
        dict.put("cat","小猫");
        dict.put("dog","小狗");
        dict.put("bird","小鸟");

    }

    @Override
    public String process(String request) {
        return dict.getOrDefault(request,"这超出了我的知识范围");
    }

    public static void main(String[] args) throws IOException {
        UdpDictServer server = new UdpDictServer(9090);
        server.start();
    }
}

在这里插入图片描述
在这里插入图片描述

当然!以下是一个简单的Python UDP客户端服务端的代码示例: UDP服务端代码: ```python import socket # 创建一个UDP socket server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 绑定IP地址和端口号 server_address = ('localhost', 12345) server_socket.bind(server_address) print("UDP服务端已启动,等待客户端发送消息...") while True: # 接收客户端发送的数据和客户端地址 data, client_address = server_socket.recvfrom(1024) print(f"接收到来自客户端 {client_address} 的消息:{data.decode()}") # 处理接收到的数据,这里可以根据具体需求进行相应的处理逻辑 # 向客户端发送响应数据 response = "已收到你的消息!" server_socket.sendto(response.encode(), client_address) ``` UDP客户端代码: ```python import socket # 创建一个UDP socket client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 服务端地址 server_address = ('localhost', 12345) while True: # 发送数据到服务端 message = input("请输入要发送的消息:") client_socket.sendto(message.encode(), server_address) # 接收服务端的响应数据 data, server_address = client_socket.recvfrom(1024) print(f"接收到服务端的响应:{data.decode()}") ``` 以上代码示例中,服务端使用`socket.socket()`创建一个UDP socket对象,然后绑定IP地址和端口号,并在循环中接收客户端发送的数据。客户端同样使用`socket.socket()`创建一个UDP socket对象,然后通过`sendto()`方法发送数据到服务端,并通过`recvfrom()`方法接收服务端的响应数据。 请注意,UDP是一个无连接的协议,因此在UDP通信中,客户端服务端之间并没有建立持久的连接。每次通信都是通过发送和接收数据报进行。此示例仅展示了一个简单的UDP客户端服务端实现,并未处理异常情况和错误处理等复杂情况。在实际应用中,可能需要根据具体需求进行适当的扩展和改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lhj_loveFang_1105

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值