【网络编程】UDP数据报套接字编程和TCP流套接字编程

文章目录

  • 1. 网络编程基础
    • 1.1 为什么需要网络编程?
    • 1.2 网络编程是什么?
    • 1.3 概念
  • 2. Socket套接字
  • 3. UDP数据报套接字编程
    • 3.1 DatagramSocket API
    • 3.2 DatagramPacket API
    • 3.3 InetSocketAddress API
  • 4. UDP构建服务端客户端(一发一收)
    • 4.1 创建服务端UdpServer.java:
    • 4.2 创建客户端UdpClient.java:
  • 5. UDP构建服务端客户端(翻译)
  • 6. TCP流套接字编程
    • 6.1 ServerSocket API
    • 6.2 Socket API
    • 6.3 TCP中的长短连接
  • 7. TCP构建服务端客户端(一发一收)
    • 7.1 创建服务端TcpServer.java
    • 7.2 创建客户端TcpClient.java
  • 8. 启动多个客户端

1. 网络编程基础

1.1 为什么需要网络编程?

这是因为在我们本地资源中,里面的内容并不丰富,而且下载的资源大多最终还是来源于网络。
而在网络世界中,里面有大量的资源。例如:当我们在网页中打开一个视频,听一段音乐,看一篇文章等,这些都属于网络资源(能从网络中获得的数据资源)。
这些资源都是通过网络编程进行数据传输,所以网络编程的需要是必不可少的。

1.2 网络编程是什么?

网络编程就是指网络主机通过不同的进程,以编程的方式进行网络通信(或称网络数据传输)。
1

1.3 概念

  1. 发送端:数据发送方的进程,称发送端。发送端的主机即网络通信中的源主机。
  2. 接收端:数据接受方的进程,称接受端。接受端的主机即网络通信中的目的主机。
  3. 收发端:发送端和接受端简称收发端。
    注意:
    发送端和接收端只是相对的,只是一次网络数据传输产生数据流向后的概念。
    如上图:进程1请求获得资源时,进程1就是发送端,进程2是接收端,进程2响应时,进程2就是发送端,进程1就是接收端。
  4. 服务端:提供服务的一端,称为服务端。
  5. 客户端:获取服务的一端,称为客户端。
    如上图:主机1发出请求,主机2做出响应,那么我们就可以称主机1为客户端,主机2为服务端。

2. Socket套接字

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

  1. 流套接字:使用传输层TCP协议。
    TCP的特点:
    有连接
    可靠传输
    面向字节流
    有接收缓冲区,也有发送缓冲区
    大小不限
  2. 数据报套接字:使用传输层UDP协议
    UDP的特点:
    无连接
    不可靠传输
    面向数据报
    有接收缓冲区,无发送缓冲区
    大小受限:一次最多传输64k
  3. 原始套接字:原始套接字用于自定义传输层协议,用于读写内核没有处理的IP协议数据。

3. UDP数据报套接字编程

3.1 DatagramSocket API

DatagramSocket 是UDP Socket,用于发送和接收UDP数据报。

DatagramSocket 构造方法:

方法作用
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端)
        //创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口DatagramSocket socket1 = new DatagramSocket();//创建一个UDP数据报套接字的Socket,绑定到本机9090端口DatagramSocket socket2 = new DatagramSocket(9090);

DatagramSocket 方法:

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

3.2 DatagramPacket API

DatagramPacket是UDP Socket发送和接收的数据报。

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()获取数据报中的数据

3.3 InetSocketAddress API

构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建。

InetSocketAddress ( SocketAddress 的子类 )构造方法:

方法作用
InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号

4. UDP构建服务端客户端(一发一收)

知道上面的,就可以创建一个简单的服务端客户端,一发一收,就是客户端请求服务端,请求什么,客户端收到什么。

4.1 创建服务端UdpServer.java:

public class UdpServer {//创建服务器socket,不实例化private DatagramSocket socket = null;public UdpServer(int port) throws SocketException {服务器socket绑定固定的端口socket = new DatagramSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");//服务器放入死循环中,我们并不知道客户端什么时候访问客户端,需要不停的接受客户端的UDP数据报while(true){//1.创建数据报,读取客户端发送数据DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);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] 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 {//实例化服务端,端口号为9092UdpServer udpServer = new UdpServer(9092);//启动服务端udpServer.start();}
}

4.2 创建客户端UdpClient.java:

public class UdpClient {private DatagramSocket socket = null;private String serverIp;private int serverPort;public UdpClient(String ip, int port) throws SocketException {serverIp = ip;serverPort = port;socket = new DatagramSocket();}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.发送
//            InetSocketAddress inetAddress = new InetSocketAddress(serverIp,serverPort);
//            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
//                    inetAddress);
//			  计算机内部处理数据的基本单位是字节。通过将接收到的数据转义为字节,长度要用字节长度DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serverIp),serverPort);socket.send(requestPacket);//3.读取DatagramPacket responsePacket = new DatagramPacket(new byte[4096],0,4096);socket.receive(responsePacket);String response = new String(responsePacket.getData(),0,responsePacket.getLength());//4.显示System.out.println(response );}}public static void main(String[] args) throws IOException {UdpClient udpClient = new UdpClient("127.0.0.1",9092);udpClient.start();}
}

运行结果:
33
44

5. UDP构建服务端客户端(翻译)

4中服务器并没有什么功能,那么我们也可以为服务器赋予一些功能,例如:翻译。
我们只需要基于4代码的基础上,对服务器进行修改。

创建翻译服务端UdpServer.java:

public class UdpServer {//创建服务器socket,不实例化private DatagramSocket socket = null;//翻译集合private Map<String,String> dict = new HashMap<>();public UdpServer(int port) throws SocketException {//服务器socket绑定固定的端口socket = new DatagramSocket(port);//添加单词dict.put("cat","小猫");dict.put("dog","小狗");dict.put("bird","鸟");}public void start() throws IOException {System.out.println("服务器启动!");//服务器放入死循环中,我们并不知道客户端什么时候访问客户端,需要不停的接受客户端的UDP数据报while(true){//1.创建数据报,读取客户端发送数据DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);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] req: %s, resp: %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);}}//一发一收public String process(String request){return dict.getOrDefault(request,"我还是个小菜鸡");}public static void main(String[] args) throws IOException {//实例化服务端,端口号为9092UdpServer udpServer = new UdpServer(9092);//启动服务端udpServer.start();}
}

运行结果:
在这里插入图片描述
在这里插入图片描述
其实,相对于4只是修改了一些方法和属性,那么,我们也可以重新写一个类继承4中的服务器,这样会更加的简单。

6. TCP流套接字编程

ServerSocket 是创建TCP服务端Socket的API。

6.1 ServerSocket API

ServerSocket 构造方法:

方法作用
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

ServerSocket 方法:

方法作用
Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待
void close()关闭此套接字

6.2 Socket API

Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。

Socket 构造方法:

方法作用
Socket(String host, intport)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

Socket 方法:

方法作用
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流

6.3 TCP中的长短连接

TCP发送数据时,需要先建立连接,什么时候关闭连接就决定是短连接还是长连接:

  1. 短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据。
  2. 长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。

对比以上长短连接,两者区别如下:

  1. 建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。
  2. 主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。
  3. 两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于客户端与服务端通信频繁的场景,如聊天室,实时游戏等。

7. TCP构建服务端客户端(一发一收)

7.1 创建服务端TcpServer.java

public class TcpServer {private ServerSocket serverSocket = null;private ExecutorService service = Executors.newCachedThreadPool();public TcpServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");while(true){Socket socket = serverSocket.accept();service.submit(new Runnable() {@Overridepublic void run() {processConnection(socket);}});
//            Thread thread = new Thread(() -> {
//                processConnection(socket);
//            });
//            thread.start();}}public void processConnection(Socket socket){System.out.printf("客户端上线: [%s:%d]\n",socket.getInetAddress().toString(),socket.getPort());try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()){while(true){Scanner sc = new Scanner(inputStream);if(!sc.hasNext()){System.out.printf("客户端下线: [%s:%d]\n",socket.getInetAddress().toString(),socket.getPort());break;}String request = sc.next();String response = process(request);PrintWriter writer = new PrintWriter(outputStream);writer.println(response);writer.flush();System.out.printf("[%s:%d] req: %s, resp: %s\n",socket.getInetAddress().toString(),socket.getPort(),request,response);}}catch (IOException e){e.printStackTrace();}finally {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpServer tcpServer = new TcpServer(9090);tcpServer.start();}
}

7.2 创建客户端TcpClient.java

public class TcpClient {private Socket socket = null;public TcpClient(String ip, int port) throws IOException {socket = new Socket(ip,port);}public void start(){System.out.println("客服端启动!");Scanner sc = new Scanner(System.in);try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()){while(true){System.out.println("-> ");String request = sc.next();PrintWriter writer = new PrintWriter(outputStream);writer.println(request);writer.flush();Scanner scanner = new Scanner(inputStream);String response = scanner.next();System.out.println(response);}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpClient tcpClient = new TcpClient("127.0.0.1",9090);tcpClient.start();}
}

Tcp简单翻译和Udp修改规则相同。

8. 启动多个客户端

1.这里是引用
2.在这里插入图片描述
3. 在这里插入图片描述
4.
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/149720.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java基于SSM+Vue的平时成绩管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Pytorch之shuffleNet图像分类

&#x1f482; 个人主页:风间琉璃&#x1f91f; 版权: 本文由【风间琉璃】原创、在CSDN首发、需要转载请联系博主&#x1f4ac; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 前言 ShuffleNet是Face&#xff08;旷视&#xff09;在2017年发布的一个高效率…

el-date-picker增加默认值 修改样式

预期效果 默认是这样的 但希望是直接有一个默认的当天日期&#xff0c;并且字体颜色啥的样式也要修改&#xff08;在这里假设今天是2023/10/6 功能实现 踩了坑挺多坑的&#xff0c;特此记录 官方文档 按照官方的说明&#xff0c;给v-model绑定一个字符串就可以了 在j…

【MySQL】基本查询 (一)

文章目录 一. 基础查询二. where条件子句三. NULL的比较结束语 操作如下表 //创建表结构 mysql> create table exam_result(-> id int unsigned primary key auto_increment,-> name varchar(20) not null comment 同学姓名,-> chinese float default 0.0 comment…

基于SSM的大学生就业信息管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

《Spring Boot入门》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

PyTorch入门之【AlexNet】

参考文献&#xff1a;https://www.bilibili.com/video/BV1DP411C7Bw/?spm_id_from333.999.0.0&vd_source98d31d5c9db8c0021988f2c2c25a9620 AlexNet 是一个经典的卷积神经网络模型&#xff0c;用于图像分类任务。 目录 大纲dataloadermodeltraintest 大纲 各个文件的作用&…

软件设计师_数据结构与算法基础_学习笔记

文章目录 6.1 数组与矩阵6.1.1 数组6.1.2 稀疏矩阵 6.2 线性表6.2.1 数据结构的定义6.2.2 顺序表与链表6.2.2.1 定义6.2.2.2 链表的操作 6.2.3 顺序存储和链式存储的对比6.2.4 队列、循环队列、栈6.2.4.2 循环队列队空与队满条件6.2.4.3 出入后不可能出现的序列练习 6.2.5 串6.…

Hive【Hive(六)窗口函数】

窗口函数&#xff08;window functions&#xff09; 概述 定义 窗口函数能够为每行数据划分 一个窗口&#xff0c;然后对窗口范围内的数据进行计算&#xff0c;最后将计算结果返回给该行数据。 语法 窗口函数的语法主要包括 窗口 和 函数 两个部分。其中窗口用于定义计算范围…

【计算机网络面试题(62道)】

文章目录 计算机网络面试题&#xff08;62道&#xff09;基础1.**说下计算机网络体系结构2.说一下每一层对应的网络协议有哪些&#xff1f;3.那么数据在各层之间是怎么传输的呢&#xff1f; 网络综合4.**从浏览器地址栏输入 url 到显示主页的过程&#xff1f;5.说说 DNS 的解析…

LabVIEW工业虚拟仪器的标准化实施

LabVIEW工业虚拟仪器的标准化实施 创建计算机化的测试和测量系统&#xff0c;从计算机桌面控制外部测量硬件设备&#xff0c;以及在计算机屏幕上显示的类似仪器的面板上查看来自外部设备的测试或测量数据&#xff0c;所有这些都需要虚拟仪器系统软件。该软件允许用户执行所有这…

VL53L5CX驱动开发(1)----驱动TOF进行区域检测

VL53L5CX驱动开发----1.驱动TOF进行区域检测 闪烁定义视频教学样品申请源码下载主要特点硬件准备技术规格系统框图应用示意图区域映射生成STM32CUBEMX选择MCU 串口配置IIC配置X-CUBE-TOF1串口重定向代码配置Tera Term配置演示结果 闪烁定义 VL53L5CX是一款先进的飞行感应&…

总结二:linux面经

文章目录 1、 Linux中查看进程运行状态的指令、查看内存使用情况的指令、tar解压文件的参数。2、文件权限怎么修改&#xff1f;3、说说常用的Linux命令&#xff1f;4、说说如何以root权限运行某个程序&#xff1f;5、 说说软链接和硬链接的区别&#xff1f;6、说说静态库和动态…

【目标检测】——PE-YOLO精读

yolo&#xff0c;暗光目标检测 论文&#xff1a;PE-YOLO 1. 简介 卷积神经网络&#xff08;CNNs&#xff09;在近年来如何推动了物体检测的发展。许多检测器已经被提出&#xff0c;而且在许多基准数据集上的性能正在不断提高。然而&#xff0c;大多数现有的检测器都是在正常条…

1700*C. Number of Ways(贪心前缀和)

Problem - 466C - Codeforces Number of Ways - 洛谷 解析&#xff1a; 首先判断所有数总和是否能被三整除。 之后遍历前缀和数组&#xff0c;如果某个位置的前缀和等于sum/3&#xff0c;则记录。 某个位置前缀和等于sum/3*2则记录答案。 注意由于分成三份&#xff0c;所以同…

Qt 设置软件的版本信息:QMake、CMake工程

本文借鉴了Qt 设置软件的版本信息 - 疯狂delphi - 博客园 (cnblogs.com) 在原文基础增加了CMake工程实现的方法。 Qt设置软件的版本等信息 对于Qt开发的软件&#xff0c;我们如何去方便的查看其软件的版本信息。这里提供了几种方式。 在运行程序期间设置版本信息 大部分的程序…

黑马点评-01基于Redis实现短信登陆的功能

环境准备 当前模型 nginx服务器的作用 手机或者app端向nginx服务器发起请求,nginx基于七层模型走的是HTTP协议,可以实现基于Lua直接绕开tomcat访问Redis nginx也可以作为静态资源服务器,轻松扛下上万并发并负载均衡到下游的tomcat服务器,利用集群支撑起整个项目 使用nginx部…

二分查找:34. 在排序数组中查找元素的第一个和最后一个位置

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《算法》 文章目录 前言一、题目解析二、解题思路1. 暴力查找2. 一次二分查找 部分遍历3. 两次二分查找分别查找左右端点1.查找区间左端点2. 查找区间右端点 三、代码实现总结 前言 本篇文…

力扣 -- 873. 最长的斐波那契子序列的长度

解题步骤&#xff1a; 参考代码&#xff1a; class Solution { public:int lenLongestFibSubseq(vector<int>& nums) {int nnums.size();unordered_map<int,int> hash;for(int i0;i<n;i){hash[nums[i]]i;}int ret2;vector<vector<int>> dp(n,v…

基于SSM的旅游网站设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…