[JAVAee]网络编程-套接字Socket

目录

基本概念

发送端与接收端

请求与响应

​编辑客户端与服务器

Socket套接字 

分类

数据报套接字

流套接字传输模型  

UDP数据报套接字编程

DatagramSocket API

DatagramPacket API

InetSocketAddress API

示例一:

示例二:

TCP流数据报套接字编程

ServerSocket API

Socket API

示例一:

 


网络编程指的是,网络上的主机的不同进程通过编程的方式实现网络通信.同一主机下只要满足不同进程间的通信就可以成为"网络通信"

基本概念

发送端与接收端

在网络通信中:

作为发送数据的进程称为"发送端",发送端主机即网络通信中的"源主机" 

作为接收数据的进程称为"接收端",接收端主机即网络通信中的"目的主机"

注意:网络通信中的发送端与接收端都是相对的.

请求与响应

一般来说,一次网络通信中设计到两次数据传输:

  • 第一次:A端向B端发送的请求
  • 第二次:B端向A端发送的响应

客户端与服务器

服务器:在网络通信下,提供服务的一端.(服务可以指:响应一定的要求)

客户端:获取服务的一端

Socket套接字 

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

分类

套接字根据传输层协议主要分成:

  • 数据报套接字:使用传输层UDP协议(User Datagram Protocol)用户数据报协议
  • 流套接字:使用传输层TCP协议(Transmission Control Protocol)传输层控制协议
  • 原始套接字:用于自定义传输层协议

数据报套接字

数据报固定每次传输的字节,更像是写信,有来有回的.

流套接字传输模型  

面对的是字节流.

打电话一般,接通后就可以无节制的传输.

UDP数据报套接字编程

DatagramSocket API

构造方法

方法签名方法说明
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 length,
SocketAddress address)
构造一个DatagramPacket以用来发送数据报,发送的数据为字节
数组(第一个参数buf)中,从0到指定长度(第二个参数
length)。address指定目的主机的IP和端口号

常用方法 

方法签名方法说明
InetAddress
getAddress()
从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取
接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获
取接收端主机端口号
byte[] getData()获取数据报中的数据

InetSocketAddress API

InetSocketAddress是ScketAddress的一个子类,用来包装IP与端口号

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

示例一:

客户端像服务器发出请求,但服务器无响应版本

服务器:

public class UdpServer {private DatagramSocket socket= null;public UdpServer(int port) throws SocketException {//构造方法this.socket = new DatagramSocket(port);}public void start() throws IOException {//作为启动服务器的方法while(true){//因为不知道什么时候客户端会发送请求//作为服务器,需要不停的接收客户端的请求//创建packetbyte[] bytes = new byte[1024];DatagramPacket packet = new DatagramPacket(bytes,bytes.length);//用bytes作为接收,使用的长度为bytes的长度System.out.println("等待接收数据中...");socket.receive(packet);//还没收到之前会进行阻塞等待//此处的版本没有作出响应//我们可以打印出收到的packet中的数据看看有什么东西System.out.println("IP: " + packet.getAddress().getHostAddress());System.out.println("端口号: " + packet.getPort());System.out.printf("文本数据为: " + new String(packet.getData()));System.out.println("原始数据为: " + Arrays.toString(packet.getData()));}}public static void main(String[] args) throws IOException {UdpServer udpServer = new UdpServer(1024);udpServer.start();}
}

客户端:

方法一:
public class UdpClient {public static void main(String[] args) throws IOException {//创建SocketDatagramSocket socket = new DatagramSocket();//创建一个socket,端口号为系统随机分配//构建Packetbyte[] bytes = "Hello World".getBytes();//字符串转换成byte再塞进数组SocketAddress address = new InetSocketAddress("localhost",1024);//目的IP为本地地址,端口号为1024DatagramPacket packet = new DatagramPacket(bytes,bytes.length,address);//构建packetsocket.send(packet);//发送System.out.println("发送完成");}
}
方法二:
public class UdpClient {private DatagramSocket socket = null;//socketprivate String serverIp;private int serverPort;public UdpClient(String serverIp,int serverPort) throws SocketException {this.socket = new DatagramSocket();this.serverIp = serverIp;this.serverPort = serverPort;}public void start() throws IOException {System.out.println("客户端启动");Scanner scanner = new Scanner(System.in);while(true){System.out.println("输入:");String text = scanner.next();if(text.equals("exit")){System.out.println("再见");break;}//需要用InetAddress将字符串钟的IP转换成地址形式//SocketAddress address = new InetSocketAddress("localhost",1024);//也可以创建一个实例进行包装IP与端口号//此处的长度是字节的长度噢,注意单位DatagramPacket packet = new DatagramPacket(text.getBytes(),text.getBytes().length,InetAddress.getByName(serverIp),serverPort);socket.send(packet);System.out.println("发送成功");}}public static void main(String[] args) throws IOException {UdpClient client = new UdpClient("127.0.0.1",1024);client.start();}

先启动服务器后启动客户端发送.

记得打开IDEA可以同时运行两个进程的选项噢!

服务器接收到的信息为:

示例二:

做一个服务器对客户端有响应的版本

简单的英汉翻译

服务器:

public class UdpServerResponse{private DatagramSocket socket= null;public UdpServerResponse(int port) throws SocketException {//构造方法this.socket = new DatagramSocket(port);}public void start() throws IOException {//启动服务器while(true){byte[] bytes = new byte[1024];DatagramPacket receivePacket = new DatagramPacket(bytes,bytes.length);//创建包来接收System.out.println("等待接收数据中...");socket.receive(receivePacket);//接收包String request = new String(receivePacket.getData(),0,receivePacket.getLength());//根据接收到的包转换成字符串String response = process(request);//对请求进行分析//记得是getSocketAddress噢里面通常包含了IP与端口号DatagramPacket sendPacket = new DatagramPacket(response.getBytes(),response.getBytes().length,receivePacket.getSocketAddress());socket.send(sendPacket);//对客户端作出响应System.out.println("客户端IP: " + receivePacket.getAddress());System.out.println("客户端端口号: " + receivePacket.getPort());System.out.println("收到的文本: " + request);System.out.println("返回的文本: " + response);}}public String process(String request){//解析请求,看看要做什么//这里就做一个英汉翻译吧HashMap<String,String> map = new HashMap<>();map.put("人","human");map.put("猫","cat");map.put("狗","dog");return map.getOrDefault(request,"查阅失败");}public static void main(String[] args) throws IOException {UdpServerResponse udpServerResponse = new UdpServerResponse(1024);udpServerResponse.start();}
}

客户端:

public class UdpClientResponse {private DatagramSocket socket = null;private String serverIp;private int serverPort;public UdpClientResponse(String serverIp,int serverPort) throws SocketException {this.serverIp = serverIp;this.serverPort = serverPort;socket = new DatagramSocket();}public void start() throws IOException {System.out.println("客户端启动");Scanner scanner = new Scanner(System.in);while (true) {System.out.print("输入: ");String request = scanner.next();if(request.equals("exit")){System.out.println("再见!");break;}//根据请求创建包DatagramPacket sendPacket = new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName("127.0.0.1"),1024);socket.send(sendPacket);System.out.println("发送成功");DatagramPacket receivePacket = new DatagramPacket(new byte[1024],1024);//创建接收包socket.receive(receivePacket);String receive = new String(receivePacket.getData(),0,receivePacket.getLength());System.out.println(receive);}}public static void main(String[] args) throws IOException {UdpClientResponse udpClientResponse = new UdpClientResponse("127.0.0.1",1024);udpClientResponse.start();}
}

服务器的打印

客户端的打印

TCP流数据报套接字编程

ServerSocket API

创建TCP服务端的API

构造方法

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

方法

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

Socket API

用来建立链接后保存对方的信息

构造方法:

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

常用方法 

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

在TCP协议中的连接还分为长连接与短链接.

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

示例一:

一请求一响应

此处为长连接(把代码里的while(true)去掉就是短连接啦!只进行一次请求响应)

服务器:

对于服务器来说,每次与客户端连接后会创建一个socket来暂时存储客户端的信息数据

断开连接后,记得要将这个存储客户端数据的socket进行close释放掉

在服务器进程中,一个客户端socket会占用文件描述符的一个位置,一个服务器可能会要与成千上万个客户端进行通信,不释放就会将文件描述符的位置沾满造成泄露.

而服务器的serverSocket的生命周期与整个进程相当,且只有一个.所以可以不进行释放

使用线程池,用多线程的方式来运行服务器达到同时与多个客户端进行通信的功能.

public class TcpServer {private ServerSocket socket = null;public TcpServer(int port) throws IOException {socket = new ServerSocket(port);}public void start() throws IOException {//尝试链接ExecutorService threadPool = Executors.newCachedThreadPool();//创建一个线程池,一个线程对应一个客户端进行通信while (true) {Socket clientSocket = socket.accept();//会阻塞等待接受threadPool.submit(() -> {//向线程提供任务try {processConnect(clientSocket);} catch (IOException e) {e.printStackTrace();}});}}public void processConnect(Socket clientSocket) throws IOException {System.out.println("已与客户端进行链接-" + clientSocket.getInetAddress() + clientSocket.getPort());try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()){while(true){Scanner scanner = new Scanner(inputStream);//读PrintWriter printWriter = new PrintWriter(outputStream);//写if(!scanner.hasNext()){//客户端不再传输数据就断开链接System.out.println("结束");break;}String request = scanner.next();//接收请求String response = process(request);//处理请求printWriter.println(response);//向客户端写回响应printWriter.flush();//记得写回后进行刷新缓冲区System.out.println("响应:" + clientSocket.getInetAddress() + clientSocket.getPort() + "文本: "+ response);}} catch (IOException e) {e.printStackTrace();}finally {clientSocket.close();//记得要关闭}}public String process(String request){HashMap<String,String> map = new HashMap<>();map.put("人","human");map.put("猫","cat");map.put("狗","dog");return map.getOrDefault(request,"查阅失败");}public static void main(String[] args) throws IOException {TcpServer tcpServer = new TcpServer(1024);tcpServer.start();}
}

客户端:

public class TcpClient {private Socket socket = null;private String serverIp;private int serverPort;public TcpClient(String serverIp,int serverPort) throws IOException {socket = new Socket(serverIp,serverPort);//客户端随机分配端口号this.serverIp = serverIp;this.serverPort = serverPort;}public void start(){try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {//创建流对象进行写与读while(true){Scanner scanner = new Scanner(System.in);//用来写入PrintWriter printWriter = new PrintWriter(outputStream);//包装output流对象String request = scanner.next();//写请求if(request.equals("exit")){System.out.println("结束与服务器连接");break;}//把请求放到流对象中写出去printWriter.println(request);printWriter.flush();//刷新缓冲区Scanner responseScanner = new Scanner(inputStream);String response = responseScanner.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",1024);tcpClient.start();}
}

服务器打印:

 

客户端打印:

 

 


 

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

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

相关文章

LISA:通过大语言模型进行推理分割

论文&#xff1a;https://arxiv.org/pdf/2308.00692 代码&#xff1a;GitHub - dvlab-research/LISA 摘要 尽管感知系统近年来取得了显著的进步&#xff0c;但在执行视觉识别任务之前&#xff0c;它们仍然依赖于明确的人类指令来识别目标物体或类别。这样的系统缺乏主动推理…

在golang中引入私有git仓库的pkg包?引入私有Git仓库的包:在Go语言项目中轻松实现

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to Golang Language.✨✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1…

《吐血整理》高级系列教程-吃透Fiddler抓包教程(37)-掌握Fiddler中Fiddler Script用法你有多牛逼-下

1.简介 Fiddler是一款强大的HTTP抓包工具&#xff0c;它能记录所有客户端和服务器的http和https请求&#xff0c;允许你监视&#xff0c;设置断点&#xff0c;甚至修改输入输出数据. 使用Fiddler无论对开发还是测试来说&#xff0c;都有很大的帮助。Fiddler提供的功能基本上能…

系统架构设计高级技能 · 软件可靠性分析与设计(三)【系统架构设计师】

系列文章目录 系统架构设计高级技能 软件架构概念、架构风格、ABSD、架构复用、DSSA&#xff08;一&#xff09;【系统架构设计师】 系统架构设计高级技能 系统质量属性与架构评估&#xff08;二&#xff09;【系统架构设计师】 系统架构设计高级技能 软件可靠性分析与设计…

Redis 加入服务列表自启动

1、下载reids windows版本&#xff0c;选择zip格式下载 2、解压zip&#xff0c;并进入路径&#xff1b; 3、命令提示符&#xff08;cmd&#xff09; 进入解压后的路径后&#xff0c;输入指令&#xff1a;redis-server --service-install redis.windows.conf&#xff1b; 4、如…

Linux计划任务管理at、crond

一、单次任务at at命令可以设置在一个指定的时间执行一个指定任务&#xff0c;只能执行一次&#xff0c;使用前确认系统开启了atd服务。 例如&#xff1a;定时执行某命令或脚本&#xff0c; 1、输入at 19:00&#xff0c;回车&#xff1b; 2、输入需要执行的命令或脚本文件&am…

笔记本WIFI连接无网络【实测有效,不用重启电脑】

笔记本Wifi连接无网络实测有效解决方案 问题描述&#xff1a; 笔记本买来一段时间后&#xff0c;WIFI网络连接开机一段时间还正常连接&#xff0c;但是过一段时间显示网络连接不上&#xff0c;重启电脑太麻烦&#xff0c;选择编写重启网络脚本解决。三步解决问题。 解决方案&a…

每日一练 | 华为认证真题练习Day92

1、TFTP基于TCP协议。 A. 对 B. 错 2、Trunk类型的端口和Hybrid类型的端口在接收数据帧时的处理方式相同。 A. True B. False 3、以下哪种PPPoE的报文是非单播方式发送的&#xff1f; A. PADS B. PADI C. PADO D. PADR 4、HDLC帧由以下哪些字段组成&#xff1f;&#x…

10_Vue3 其它的组合式API(Composition API)

Vue3 中的其它组合式API 1.shallowReactive 与 shallowRef 2. readonly 与 shallowReadonly 3.toRaw 与 markRaw 4.customRef 5.provide 与 inject 6.响应式数据的判断

HTTP连接之出现400 Bad Request分析

1、400简介 400是一种HTTP状态码&#xff0c;告诉客户端它发送了一条异常请求。400页面是当用户在打开网页时&#xff0c;返回给用户界面带有400提示符的页面。其含义是你访问的页面域名不存在或者请求错误。主要分为两种。 1、语义有误&#xff0c;当前请求无法被服务器理解…

使用Python将Word文档转换为PDF的方法

摘要&#xff1a; 文介绍了如何使用Python编程语言将Word文档转换为PDF格式的方法。我们将使用python-docx和pywin32库来实现这个功能&#xff0c;这些库提供了与Microsoft Word应用程序的交互能力。 正文&#xff1a; 在现实生活和工作中&#xff0c;我们可能会遇到将Word文…

Python 调用自定义函数

新手入坑。 通常我们需要把公共函数提出来&#xff0c;作为公共资源调用。也避免了代码的重复书写。 比如我们在项目内创建我们的py脚本路径如下&#xff1a; 在公共方法中定义方法&#xff1a; class CommonMethods:def dataFormat(df):dataList []for row in range(0, df.…

mac安装open3d时候出现错误

在测试open3d是否正常顺利安装时&#xff0c;出现了如下错误&#xff1a; python -c "import open3d as o3d; print(o3d.__version__)" Traceback (most recent call last):File "<string>", line 1, in <module>File "/Users/huangzhe/…

根文件系统制作

1.官网下载工具 制作工具&#xff1a;busybox https://busybox.net/downloads/ 2.制作根文件系统 2.1准备工作 a.把压缩包放在FSP1M目录下&#xff0c;并解压 2.2正式开始 2.2.1配置交叉编译工具链 1. 打开Makefile文件 2. 修改ARCH &#xff1f;$(SUBARCH) &#xf…

将http协议升级为https协议——域名平台部分的设置

为远程群晖NAS的自定义域名免费申请SSL证书 文章目录 为远程群晖NAS的自定义域名免费申请SSL证书前言1. 向域名平台申请SSL证书1.1 购买“免费证书” 2. 进一步进行创建证书设置2.1 对证书的关联域名进行补充 3. 云解析DNS3.1 进行验证信息 前言 我们可以成功地将自己购买的域…

新手注意事项-visual studio 来实现别踩白块儿

自己之前为了熟悉easyx练习过一个简单的项目&#xff0c;别踩白块儿&#xff0c;链接在这里&#xff0c;别踩白块儿&#xff0c;当时比较稚嫩&#xff0c;很多东西都不会&#xff0c;可以说是只知道最基本的语法&#xff0c;头文件都不知道&#xff0c;一个一个查资料弄懂的&am…

【LeetCode】287. 寻找重复数

287 . 寻找重复数&#xff08;中等&#xff09; 方法 快慢指针 思路 要解决这道题首先要理解如何将输入的数组看作为链表。对于数组 nums 中的数字范围在 [1, n]&#xff0c;考虑两种情况&#xff1a; 如果数组中没有重复的数字&#xff0c;以 [1, 3, 4, 2] 为例&#xff0c;将…

C++ | C++11新特性(上)

目录 前言 一、列表初始化 二、声明 1、auto 2、decltype 3、nullptr 三、STL容器的变化 四、右值引用与移动语义 1、左值与左值引用 2、右值与右值引用 3、右值引用与左值引用的比较 4、右值引用的场景及意义 &#xff08;1&#xff09;做参数 &#xff08;2&a…

影响亚马逊Listing转化率的14大因素你知道吗?

我们都知道亚马逊listing转化率对于链接的推新和维稳来说有多么重要&#xff0c;只要转化率的比值无法达到整体市场平均比值的及格线&#xff0c;你就很可能会慢慢被亚马逊的飞轮算法所淘汰。 那么&#xff0c;具体是哪些因素在影响着你的listing转化率呢?这里我们可以分为显…

wm8960没有声音

最近在imx6ull上调试这个声卡&#xff0c;用官方的镜像是能发声的&#xff0c;换到自己做的镜像上&#xff0c;就没有声音。 记录一下过程&#xff1a; 内核和设备树。只要有下面的显示&#xff0c;就说明加载成功。 再看一下aplay的显示 到此&#xff0c;驱动都是正常的。但…