网络编程—Socket套接字(UDP)

上篇文章:

网络编程---网络概念https://blog.csdn.net/sniper_fandc/article/details/146923380?fromshare=blogdetail&sharetype=blogdetail&sharerId=146923380&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link

目录

[1 概念](#1 概念)

[2 Socket套接字](#2 Socket套接字)

[3 UDP数据报套接字](#3 UDP数据报套接字)


1 概念

**(1)网络编程:**指网络上的主机,通过不同的进程,以编程的方式实现网络通信(网络数据传输)。

进程具有隔离性,因此不同的进程间要通信就得通过共享的公共区域来交换数据,网卡即是一种共享公共区域。

**(2)客户端(Client)/服务器(Server):**客户端是数据发送方,服务器是数据接收方,由于服务器是被动接收数据,不知道客户端什么时候发送数据,因此服务器经常是24小时运行。

**(3)请求(request)和响应(response):**客户端发送给服务器的数据,服务器返回给客户端的数据。

**(4)客户端/服务器交互方式:**一问一答(浏览网页)、多问一答(上传文件)、一问多答(下载文件)和多问多答(远程控制、游戏串流(手机连接电脑玩电脑游戏))。

2 Socket套接字

Socket即是传输层(操作系统)提供给程序员的API,有基于TCP和UDP两种类型,原始的API是C语言的,经过JVM包装后,形成了Java的Socket API。

3 UDP数据报套接字

基于UDP的Socket主要是DatagramSocket,用于发送和接收UDP数据报,作用和操作方式都类似文件(打开Socket文件(对应网卡),发送/接收数据报,关闭文件)。

|--------------------------------|--------------------------------------------------|
| 构造方法/方法 | 含义 |
| DatagramSocket() | 构造方法,创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端) |
| DatagramSocket(int port) | 构造方法,创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端) |
| void receive(DatagramPacket p) | 从套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待) |
| void send(DatagramPacket p) | 从套接字发送数据报包(不会阻塞等待,直接发送) |
| void close() | 关闭数据报套接字 |

DatagramPacket是数据报的API,用来组织需要发送和接收的数据。

|----------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|
| 构造方法/方法 | 含义 |
| DatagramPacket(byte[] buf, int length) | 构造方法,创建一个DatagramPacket用来接收数据报,接收的数据保存在buf,length是数据长度 |
| DatagramPacket(byte[] buf, int offset, int length, SocketAddress address | 构造方法,创建一个DatagramPacket用来发送数据报,发送的数据保存在buf,offset是起始下标,length是数据长度,address指定目标主机的IP和端口号 |
| InetAddress getAddress() | 从接收的数据报中,获取发送端主机IP地址,或从发送的数据报中,获取接收端主机IP地址 |
| int getPort() | 从接收的数据报中,获取发送端主机的端口号,或从发送的数据报中,获 取接收端主机端口号 |
| byte[] getData() | 获取数据报中的数据 |

而使用InetSocketAddress(InetAddress addr, int port)即可创建一个Socket地址,包含IP地址和端口号,它是SocketAddress的子类。

下面利用UDP数据报套接字实现一个回显服务器,回显服务器是指客户端发送什么,服务器就返回什么。

java 复制代码
public class UdpServer {

    //回显服务器端口号

    private  final int PORT = 8000;

    public  DatagramSocket datagramSocket = null;

    //通过端口创建udp服务器(本质是打开一个socket文件)

    public UdpServer() throws SocketException {

        datagramSocket = new DatagramSocket(PORT);

    }

    //启动服务器

    public void start() throws IOException {

        System.out.println("服务器已启动");

        //服务器需要24小时启动因此写成死循环

        while(true){

            //1.创建接收请求的数据报(分配字节数组空间)并接收请求

            DatagramPacket datagramPacket = new DatagramPacket(new byte[4096],4096);

            //该方法会一直阻塞等待直到客户端发送请求

            datagramSocket.receive(datagramPacket);

            //2.解析请求构造响应数据报

            String request = new String(datagramPacket.getData(),0,datagramPacket.getLength());

            //3.根据请求构造响应(服务器业务逻辑)

            String response = process(request);

            //要用指定发送地址的构造方法(发送地址可以从接收的请求数据报中获取)

            DatagramPacket datagramPacketResponse = new DatagramPacket(response.getBytes(),response.getBytes().length,

                    datagramPacket.getSocketAddress());

            //4.返回响应

            datagramSocket.send(datagramPacketResponse);

            System.out.printf("[%s:%d] request=%s;response=%s\n",datagramPacket.getAddress().toString(),datagramPacket.getPort(),

                    request,response);

        }

    }

    //回显服务器就是发送什么请求返回什么响应

    private String process(String request) {

        return request;

    }



    public static void main(String[] args) throws IOException {

        //启动服务器

        UdpServer server = new UdpServer();

        server.start();

    }

}

public class UdpClient {

    //创建客户端

    private DatagramSocket socket = null;

    public UdpClient() throws SocketException {

        //客户端一般随机生成端口号

        socket = new DatagramSocket();

    }

    //启动客户端

    public void start() throws IOException {

        Scanner scanner = new Scanner(System.in);

        while(true){

            //1.构造请求

            System.out.print(">");

            String req = scanner.next();

            //构造的请求数据报既要包含数据又要包含地址(IP+端口)

            DatagramPacket request = new DatagramPacket(req.getBytes(),req.getBytes().length,

                    InetAddress.getByName("127.0.0.1"),8000);

            //2.发送请求

            socket.send(request);

            //3.接受响应并解析响应

            DatagramPacket response = new DatagramPacket(new byte[4096],4096);

            socket.receive(response);

            String resp = new String(response.getData(),0,response.getLength());

            //4.将响应返回给用户

            System.out.printf("request=%s,response=%s\n",req,resp);

        }

    }



    public static void main(String[] args) throws IOException {

        UdpClient udpClient = new UdpClient();

        udpClient.start();

    }

}

在服务器代码中,需要注意response.getBytes().length不等于response.length(),前一个方法获取的是字节长度,而后一个方法获取的是字符长度,当字符中有中文时,字节长度和字符长度并不相等,因此不能替换。而字符串"127.0.0.1"是环回IP,表示本机(自己发给自己)。

根据结果显示,虽然发送的一条请求hello World,但是却被拆成hello和World两条请求发送了,这是因为这里使用Scanner类的next()方法,该方法以空格作为结束进行分割,因此发送两条请求。如果向发送一条,就可以使用nextLine(),该方法以换行符结束。

下篇文章:

网络编程---Socket套接字(TCP)https://blog.csdn.net/sniper_fandc/article/details/146923783?fromshare=blogdetail&sharetype=blogdetail&sharerId=146923783&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link

相关推荐
.R^O^2 分钟前
计算机知识
linux·服务器·网络·安全
sky.fly13 分钟前
三层路由器,SSH远程登录访问路由器,通过telnet远程登录访问路由器(不安全),路由器的基本设置之多网络互联解决办法:单臂路由
服务器·网络·计算机网络·智能路由器
00后程序员张24 分钟前
Flutter 从零到一
websocket·网络协议·tcp/ip·http·网络安全·https·udp
卡戎-caryon26 分钟前
【Linux网络与网络编程】11.数据链路层mac帧协议&&ARP协议
linux·服务器·网络·笔记·tcp/ip·数据链路层
我最厉害。,。1 小时前
XSS 跨站&Cookie 盗取&表单劫持&网络钓鱼&溯源分析&项目平台框架
android·网络·xss
稀饭过霍1 小时前
【linux】命令收集
linux·服务器·网络
珹洺1 小时前
Linux红帽:RHCSA认证知识讲解(十 三)在serverb上破解root密码
linux·运维·服务器·网络·后端
C_VuI2 小时前
http/https请求解析
网络协议·http·https
格格Code3 小时前
tcp和udp的数据传输过程以及区别
网络·网络协议·udp
小吃饱了3 小时前
OSPF综合实验
网络·智能路由器