当前位置: 首页 > news >正文

(网络编程)网络编程套接字 UDP的socket API 代码解析

网络编程基础 

为什么需要网络编程?--丰富的网络资源
用户在浏览器中,打开在线视频网站,如优酷看视频,实质是通过网络,获取到网络上的一个视频资源。

与本地打开视频文件类似,只是视频文件这个资源的来源是网络。
相比本地资源来说,网络提供了更为丰富的网络资源:

所谓的网络资源,其实就是在网络中可以获取的各种数据资源。而所有的网络资源,都是通过网络编程来进行数据传输的。
什么是网络编程
网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信:网络数据传输

当然,我们只要满足进程不同就行;所以即便是同一个主机,只要是不同进程,基于网络来传输数
据,也属于网络编程。
特殊的,对于开发来说,在条件有限的情况下,一般也都是在一个主机中运行多个进程来完成网络编程。
但是,我们一定要明确,我们的目的是提供网络上不同主机,基于网络来传输数据资源:
进程A:编程来获取网络资源
进程B:编程来提供网络资源
​​​​​

网络编程中的基本概念 

1.发送端和接收端
在一次网络数据传输时:
发送端:数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机。
接收端:数据的接收方进程,称为接收端。接收端主机即网络通信中的目的主机。
收发端:发送端和接收端两端,也简称为收发端。
注意:发送端和接收端只是相对的,只是一次网络数据传输产生数据流向后的概念。
 

2.请求和响应
一般来说,获取一个网络资源,涉及到两次网络数据传输:
第一次:请求数据的发送
第二次:响应数据的发送。
好比在快餐店点一份炒饭:
先要发起请求:点一份炒饭,再有快餐店提供的对应响应:提供一份炒饭

3.客户端和服务端
服务端:在常见的网络数据传输场景下,把提供服务的一方进程,称为服务端,可以提供对外提供服务。
客户端:获取服务的一方进程,称为客户端。
对于服务来说,一般是提供:客户端获取服务资源

Socket套接字 

概念

Socket(套接字) 是计算机网络中用于进程间通信的一种机制,它允许不同主机或同一主机上的不同进程之间进行数据交换。Socket 是应用层与传输层之间的抽象接口,为程序提供了使用网络协议(如 TCP/IP)的标准化方式。
Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元;基于Socket套接字的网络程序开发就是网络编程。
分类
Socket套接字主要针对传输层协议划分为如下三类:
1.流套接字:使用传输层TCP协议
TCP,即Transmission ControlProtocol (传输控制协议),传输层协议。
以下为TCP的特点:
有连接
   可靠传输   面向字节流   有接收缓冲区,也有发送缓冲区   大小不限
对于字节流来说,可以简单的理解为,传输数据是基于10流,流式数据的特征就是在I0流没有关闭的情况下,是无边界的数据,可以多次发送,也可以分开多次接收。

2.数据报套接字:使用传输层UDP协议
UDP,即User Datagram Protocol(用户数据报协议),传输层协议。
以下为UDP的特点:
无连接   不可靠传输   面向数据报   有接收缓冲区,无发送缓冲区   大小受限:一次最多传输64k
对于数据报来说,可以简单的理解为,传输数据是一块一块的,发送一块数据假如100个字节,必须一次发送,接收也必须一次接收100个字节,而不能分100次,每次接收1个字节。


3.原始套接字
原始套接字用于自定义传输层协议,用于读写内核没有处理的IP协议数据。

不能指望,一个数据包发送之后,100%到达对方
可靠传输的意思,不是保证数据包100%到达,而是尽可能的提高传输成功的概率.

不可靠传输,只是把数据发了,就不管了

对于TCP来说,TCP协议中,就保存了对端的信息.
A和B通信,A和B先建立连接
让A保存,B的信息,B保存A的信息(彼此之间知道,谁是和他建立连接的那个)
对于UDP来说,UDP协议本身不保存对方的信息--就是无连接

面向字节流vs面向数据报
面向字节流,读写数据的时候,是以字节为单位   支持任意长度=>粘包问题
面向数据报,读写数据的时候,以一个数据报为单位(不是字符)
不存在粘包>长度限制  一次必须读写一个UDP数据报,不能是半个
半双工vS全双工
一个通信链路,支持双向通信(能读,也能写)
一个通信链路,只支持单向通信~~(要么读,要么写)

UDP的socket API 

Java数据报套接字通信模型
对于UDP协议来说,具有无连接,面向数据报的特征,即每次都是没有建立连接,并且一次发送全部的数据报,一次接收全部的数据报。

计算机中的"文件"通常是一个"广义的概念"
文件还能代指一些硬件设备(操作系统管理硬件设备,也是抽象成文件,统一管理的)
网卡=>socket 文件   操作网卡的时候,流程和操作普通文件差不多
也会在文件描述符表中分配一个表项
操作网卡的时候流程和操作普通文件差不多     打开->读写->关闭
其中,打开这个操作也会在文件描述符表中分配一个表项      操作网卡,直接操作不好操作.
把操作网卡转换成操作socket文件.socket文件就相当于"网卡的遥控器"

就是电脑的网卡--操作系统当做文件来管理
java中使用UDP协议通信,主要基于DatagramSocket类来创建数据报套接字,并使用
DatagramPacket作为发送或接收的UDP数据报。对于一次发送及接收UDP数据报的流程如下:

以上只是一次发送端的UDP数据报发送,及接收端的数据报接收,并没有返回的数据。也就是只有请求,没有响应。对于一个服务端来说,重要的是提供多个客户端的请求处理及响应,流程如下:

DatagramSocket 构造方法:

这里传输的就是端口号,用于区分主机上的不同的应用程序

DatagramSocket 方法:

DatagramPacket 构造方法:

DatagramPacket 方法:

package thread;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpEchoServer {private DatagramSocket socket=null;private String process(String request){return request;}public UdpEchoServer(int port) throws SocketException {socket=new DatagramSocket(port);}public void start() throws IOException {// 启动服务器System.out.println("服务器启动");while (true){// 循环一次, 就相当于处理一次请求.// 处理请求的过程, 典型的服务器都是分成三个步骤的.// 1. 读取请求并解析.//    DatagramPacket 表示一个 UDP 数据报. 此处传入的字节数组, 就保存 UDP 的载荷部分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.把响应返回给客户端//    根据 response 构造 DatagramPacket, 发送给客户端.//    此处不能使用 response.length()DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length);//    此处还不能直接发送. UDP 协议自身没有保存对方的信息(不知道发给谁)//    需要指定 目的 ip 和 目的端口.socket.send(responsePacket);//4,打印一个日志System.out.printf("[%s:%d] req:%s,resp:%d\n",responsePacket.getAddress().toString(),requestPacket.getPort(),request,response);}}}

DatagramPacket有三个方法.
1)getAddress 只拿到 IP
2)getPort 只拿到端口
3)getSocketAddress同时拿到IP和端口(IP和端口通过
一个lnetAddress 对象表示)

后续客户端给服务器发的数据,就是发字符串.(echo,客户端发一个hello,服务器返回hello)
本身收到的DatagramPacket 的二进制数据从 String转来的.只是还原回去

客户端访问服务器,serverlp是目的ip,serverport 是目的端口
源ip客户端所在的主机ip,源端口,应该是随机搞一个端口(操作系统分配空闲端口)

一定是不能填写serverPort   必须使用无参数版本

进阶--代码解析

端口号是区分同一个主机不同的应用程序的.
同一时刻,不能有两个程序使用同一个端口
(操作系统中,一个程序尝试关联一个非空闲的端口,就会关联失败)

如果客户端是固定端口,很可能客户端运行的时候,这个端口被别的程序占用,就会使得当前这个程序运行失败!!
客户端是在用户手里,无法控制你的用户电脑上都运行啥样的程序
服务器是在程序员手里的,就算出现端口冲突,程序员也方便处理

构造请求的数据报.
1.载荷
2.目的IP目的端口

127.0.0.1特殊的IP    环回IP   表示当前这个主机.
无论你主机的IP真实是啥,都可以使用127.0.0.1代替.
类似于this
由于此时,客户端和服务器在同一个主机上,就可以使用127.0.0.1来访问
如果是不同主机,就需要填写其他的IP了.

客户端和服务器在同一个主机上     是否联网都是可以的.
不同主机上必须联网了

不同的主机要进行这样的通讯:(1)在同一个局域网下(2)部署在云服务器上

若是想部署在虚拟机:取决于虚拟机的网络是怎么设置的.
虚拟机网络设置规格主要有三种典型:
1.桥接网络(可以)
2.NAT网络(有的虚拟机软件可以,有的不行)
3.Host Only网络(不可以)

(为啥没有云服务器不行?NAT机制搞鬼)
把程序部署到云服务器上,就可以访问到云服务器了

DatagramPacket  UDP面向数据报协议.
发送接收的时候,以数据报作为基本单位

socket正常是需要释放的

这个socket都是跟随整个进程的.   此时就不需要单独close.
进程退出,进程内部的pcb也就会销毁,里面的文件描述符表也就释放了.

部署: 启动服务器:类似于idea中点一下运行按钮     java-jar jar包名

启动客户端(本地的电脑)   把连接的服务器的IP地址,改成云服务器的IP

ServerSocket   专门给服务器用的
Socket   服务器和客户端都会用
TCP的一个核心特点,面向字节流.    读写数据的基本单位就是字节byte

虽然同一个端口,但是如果协议不同,不会冲突的

这个操作只是把数据放到"发送缓冲区"中    还没有真正写入到网卡里.
这个发送缓存区就是指的是内存空间.

flush方法来"冲刷缓冲区"

其中,println行为是自动加上\n

如果修改成了下面的这样:

这个时候,数据是发过去了的   服务器收到了的     服务器没有真正处理.

判定收到的数据中是否包含"空白符":换行,回车,空格,制表符,翻页符.....
遇到空白符,认为是一个"完整的next"
在遇到之前,都会阻塞.

暗暗约定,一个请求/响应使用\n作为结束标记
对端读的时候,也是读到\n就结束(认为是读到一个完整的请求了)

UDP就是以 DatagramPacket 作为单位的.,TCP则是字节为单位.
实际上一个请求,往往是由多个字节构成的

每个客户端连接,都会创建一个新的.
每个客户端断开连接,这个对象也就可以不要了

一个服务器要能同时给多个客户端提供服务

accept 就是接受客户端发的连接请求

socket 是基于TCP的  TCP是有连接的 可以理解为建立连接的过程

无法同时等待accept和等待用户请求,等待用户发请求的时候,没法等accept.
这个时候,有新的客户端连过来了,也无法接通电话.

如果客户端1不发请求,服务器就会阻塞在hasNext 这里

此时就需要使用多线程来解决这个问题


文章转载自:

http://m8uuHltL.ybyLn.cn
http://hvE21mtH.ybyLn.cn
http://Rw3zci4t.ybyLn.cn
http://1OfVbysA.ybyLn.cn
http://QdO5uBO9.ybyLn.cn
http://EsvrmX5d.ybyLn.cn
http://KC38ufN0.ybyLn.cn
http://5ahMUhf3.ybyLn.cn
http://hWRZqs5i.ybyLn.cn
http://U54Cvm2m.ybyLn.cn
http://86i29I8N.ybyLn.cn
http://hEgfdfx5.ybyLn.cn
http://gHH5QVxL.ybyLn.cn
http://9rbj04Gd.ybyLn.cn
http://Di2sREcM.ybyLn.cn
http://1wqkfVSm.ybyLn.cn
http://u9sXlEz4.ybyLn.cn
http://oaddmWCr.ybyLn.cn
http://Y3C8RmXx.ybyLn.cn
http://Ho8e8cBY.ybyLn.cn
http://7cHcRh0B.ybyLn.cn
http://9Ago1w05.ybyLn.cn
http://I4SlpyZk.ybyLn.cn
http://WpVXp8iK.ybyLn.cn
http://QvsGdDxL.ybyLn.cn
http://Q13zpCGK.ybyLn.cn
http://ZYBKbQqT.ybyLn.cn
http://N0XoqrWO.ybyLn.cn
http://1ne6fyR9.ybyLn.cn
http://S4PYYZhs.ybyLn.cn
http://www.dtcms.com/a/378193.html

相关文章:

  • iPhone17系列发布!跨端如何破局?
  • 把nginx、jar包、redis做成windows系统服务,开机自动启动
  • Java学习笔记四(继承)
  • Redis分布式锁的try-with-resources实现
  • 广东省省考备考(第九十七天9.11)——言语(刷题巩固第三节课)
  • ReentrantLock 源码深度解析
  • 机器人驭风而行:低空经济如何开启智能新纪元
  • 【系统架构设计(27)】信息安全技术集成
  • spring mvc 拦截器 (HandlerInterceptor )
  • 【Nginx】- 日志定期清理设置
  • 102、23种设计模式之装饰器模式(11/23)
  • SwiftData3 一剑封喉:WWDC25 的“数据剑谱”精讲,让 Core Data 老侠原地退休
  • [硬件电路-180]:集成运放,在同向放大和反向放大电路中,失调电压与信号一起被等比例放大;但在跨阻运放中,失调电压不会与电流信号等比例放大。
  • IDEA连接redis数据库时出现Failed to connect to any host resolved for DNS name.
  • kafka:【2】工作原理
  • ctfshow_web14------(PHP+switch case 穿透+SQL注入+文件读取)
  • 中电金信携手海光推出金融业云原生基础设施联合解决方案
  • 【Linux】初始Linux:从计算机历史发展、操作系统历史脉络的角度详谈Linux相关的话题,附Linux安装和用户创建(环境准备)详解
  • 软件设计师_第十章:软件工程(上)
  • ptx 简介03,ldmatrix 的应用实例解析
  • CSS的平面转换transform
  • CSS 居中
  • Golang进阶(二):设计先行
  • 腾讯深夜“亮剑”,AI编程“王座”易主?CodeBuddy发布,Claude用户一夜倒戈
  • 突破机器人通讯架构瓶颈,CAN/FD、高速485、EtherCAT,哪种总线才是最优解?
  • 【开题答辩全过程】以 _基于SSM框架的植物园管理系统的实现与设计为例,包含答辩的问题和答案
  • 哈希表封装myunordered_map和myunordered_set
  • 9.9网编项目——UDP网络聊天室
  • 单表查询-having和where区别
  • LVGL:基础对象