网络编程---Socket

文章目录

  • 网络编程基础
    • 什么是网络编程?
    • 网络编程的基本概念
  • 网络编程实现
    • Socket套接字
    • UDP网络通信流程(回显服务器)
      • 服务器:
      • 客户端
      • 完整代码示例:
    • TCP网络通信流程(回显服务器)
      • 服务器
      • 客户端
      • 完整的代码示例:
    • 两种实现方式的区别

网络编程基础

什么是网络编程?

在日常生活中,我们可以通过浏览器来查看文档资料、看视频、听音乐,这些都是获取网络资源的方式。而这些网络上的资源是如何显示在我们电脑上的呢?这就是网络编程。即:网络资源通过网络编程来进行数据传输。

官方一点的定义,网络编程是指网络上的主机通过不同的进程,以编程的方式实现网络通信。

当然,即使在一个主机中,只要是不同的进程基于网络来传输数据也属于网络编程。

网络编程的基本概念

发送端:数据的发送方进程,即网络通信中的源主机
接收端:数据的接收方进程,即网络通信中的目的主机
收发端:发送端和接收端两端。

请求:请求数据的发送。
响应:响应数据的发送。

客户端:获取服务的一方进程。
服务器:提供服务的一方进程。

上面提到的发送端和接收端其实是相对的:
在这里插入图片描述

网络编程实现

Socket套接字

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

网络通信显然是发生在传输层的过程,而传输层最出名的便是TCP协议和UDP协议了。由于TCP传输和UDP传输的特点不同。因此,Socket也被分为了俩类:TCP的Socket和UDP的Socket。下面我们分别进行介绍:
在这里插入图片描述

UDP网络通信流程(回显服务器)

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

服务器:

  1. 创建Socket 绑定端口号
	//创建一个socketprivate DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}
  1. 启动服务器
	//启动服务器public void start() throws IOException {System.out.println("服务器启动");while (true){}}

因为不知道客户端什么时候发送请求,所以使用while(true) 一直保持等待

  1. 创建Packet来接收客户端传来的数据
	//接受客户端传来的数据DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);socket.receive(requestPacket);String request = new String(requestPacket.getData(),0,requestPacket.getLength());

转化为字符串更方便使用。 接收数据的字节数组可以根据实际情况选择合适大小

  1. 根据请求计算响应
    //根据请求计算响应String response = process(request);//因为是回显服务器  就是返回和请求相同的数据  所以不用处理public String process(String request){return request;}
  1. 把响应返回给客户端
    //把响应返回给客户端DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),0,response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);

客户端

  1. 创建Sockket 确定服务器的IP和端口号
	//用于网络编程 发送数据private DatagramSocket socket = null;//指定发送数据到哪儿private String serverIP;private int serverPort;public UdpEchoClient(String serverIP, int serverPort) throws SocketException {//先new出socket   不需要指定发送的端口   客户端会自动分配一个空闲端口socket = new DatagramSocket();//构造发送去哪儿this.serverIP = serverIP;this.serverPort = serverPort;}
  1. 启动客户端
	public void start() throws IOException {Scanner scanner = new Scanner(System.in);while (true){}}

也需要使用while(true)来时刻准备接收返回的数据

  1. 发送数据
     //1.从控制台读取要发送的数据System.out.println("请输入要发送的数据");String request = scanner.next();//2.构造packetDatagramPacket requestPacker = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(this.serverIP),this.serverPort);//3.发送给服务器socket.send(requestPacker);
  1. 接收数据
    //1.从服务器读取响应数据DatagramPacket responsePacker = new DatagramPacket(new byte[4096],4096);socket.receive(responsePacker);String response = new String(responsePacker.getData(), 0,responsePacker.getLength());//2.把服务器响应显示在控制台System.out.println(response);

完整代码示例:

//服务器
public class UdpEchoServer {//创建一个socketprivate DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}//启动服务器public void start() throws IOException {System.out.println("服务器启动");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(),0,response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);//4.打印一个日志记录当前情况System.out.printf("%s - %d  request: %s  response: %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 udpEchoServer = new UdpEchoServer(9090);udpEchoServer.start();}
}
//客户端
public class UdpEchoClient {//用于网络编程 发送数据private DatagramSocket socket = null;//指定发送数据到哪儿private String serverIP;private int serverPort;public UdpEchoClient(String serverIP, int serverPort) throws SocketException {//先new出socket   不需要指定发送的端口   客户端会自动分配一个空闲端口socket = new DatagramSocket();//构造发送去哪儿this.serverIP = serverIP;this.serverPort = serverPort;}public void start() throws IOException {Scanner scanner = new Scanner(System.in);while (true){//1.从控制台读取要发送的数据System.out.println("请输入要发送的数据");String request = scanner.next();//2.构造packetDatagramPacket requestPacker = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(this.serverIP),this.serverPort);//3.发送给服务器socket.send(requestPacker);//4.从服务器读取响应数据DatagramPacket responsePacker = new DatagramPacket(new byte[4096],4096);socket.receive(responsePacker);String response = new String(responsePacker.getData(), 0,responsePacker.getLength());//5.把服务器响应显示在控制台System.out.println(response);}}public static void main(String[] args) throws IOException {UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1",9090);udpEchoClient.start();}
}

TCP网络通信流程(回显服务器)

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

服务器

  1. 创建ServerSocket用来监听
	//创建一个 监听socket 用于客户端和服务器的连接private ServerSocket listenSocket = null;public TcpEchoServer(int port) throws IOException {listenSocket = new ServerSocket(port);}
  1. 启动服务器
	//启动服务器public void start() throws IOException {System.out.println("服务器启动");while (true){}}
  1. 建立连接
Socket clientSocket = listenSocket.accept();
  1. 处理连接
processConnection(clientSocket);private void processConnection(Socket clientSocket) throws IOException {System.out.printf("已经和客户端建立连接 ip:%s  port: %d \n",clientSocket.getInetAddress().toString(),clientSocket.getPort());try (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()){while (true){//1.接受请求并解析Scanner scanner = new Scanner(inputStream);if (!scanner.hasNext()){//接受完毕  断开连接System.out.printf("断开连接 ip: %s  port: %d",clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}String request = scanner.next();//2.根据请求计算响应String response = process(request);//3.向客户端返回响应PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);printWriter.flush();//处理一次请求的详情System.out.printf("ip: %s  port: %d  request: %s  response: %s\n",clientSocket.getInetAddress().toString(),clientSocket.getPort(),request,response);}} catch (IOException e) {e.printStackTrace();}finally {clientSocket.close();}}
  1. 如果有多个客户端要建立连接,使用线程池加快处理的速度
	public void start() throws IOException {System.out.println("服务器启动");ExecutorService pool = Executors.newCachedThreadPool();while (true){//1.调用listenSocket来建立连接Socket clientSocket = listenSocket.accept();//2.处理连接  如果有多个客户端发起请求  这样的响应速度就会很慢//使用线程池pool.submit(new Runnable() {@Overridepublic void run() {try {processConnection(clientSocket);} catch (IOException e) {e.printStackTrace();}}});}}

客户端

  1. 尝试建立连接
	//创建一个socket来传输数据private Socket socket = null;//tcp需要先建立连接再传输数据   就需要先在socket里指定出服务器public TcpEchoClient(String serverIP,int serverPort) throws IOException {socket = new Socket(serverIP,serverPort);}
  1. 启动服务器
	public void start() throws IOException {}

while(true)放到了传输数据的模块

  1. 发送请求并接收响应
		Scanner scanner = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()){while (true){//1.从控制台读取数据  构造请求System.out.println("请输入要传输的数据");String request = scanner.next();//2.发送请求给服务器PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);printWriter.flush();//3.从服务器读取响应Scanner respScanner = new Scanner(inputStream);String response = respScanner.next();//4.把响应显示在客户端System.out.println(response);}}

完整的代码示例:

//服务器
public class TcpEchoServer {//创建一个 监听socket 用于客户端和服务器的连接private ServerSocket listenSocket = null;public TcpEchoServer(int port) throws IOException {listenSocket = new ServerSocket(port);}//启动服务器public void start() throws IOException {System.out.println("服务器启动");ExecutorService pool = Executors.newCachedThreadPool();while (true){//1.调用listenSocket来建立连接Socket clientSocket = listenSocket.accept();//2.处理连接  如果有多个客户端发起请求  这样的响应速度就会很慢//使用线程池pool.submit(new Runnable() {@Overridepublic void run() {try {processConnection(clientSocket);} catch (IOException e) {e.printStackTrace();}}});}}private void processConnection(Socket clientSocket) throws IOException {System.out.printf("已经和客户端建立连接 ip:%s  port: %d \n",clientSocket.getInetAddress().toString(),clientSocket.getPort());try (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()){while (true){//1.接受请求并解析Scanner scanner = new Scanner(inputStream);if (!scanner.hasNext()){//接受完毕  断开连接System.out.printf("断开连接 ip: %s  port: %d",clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}String request = scanner.next();//2.根据请求计算响应String response = process(request);//3.向客户端返回响应PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);printWriter.flush();//处理一次请求的详情System.out.printf("ip: %s  port: %d  request: %s  response: %s\n",clientSocket.getInetAddress().toString(),clientSocket.getPort(),request,response);}} catch (IOException e) {e.printStackTrace();}finally {clientSocket.close();}}//处理响应public String process(String request){return request;}public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);tcpEchoServer.start();}
}
//客户端
public class TcpEchoClient {//创建一个socket来传输数据private Socket socket = null;//tcp需要先建立连接再传输数据   就需要先在socket里指定出服务器public TcpEchoClient(String serverIP,int serverPort) throws IOException {socket = new Socket(serverIP,serverPort);}public void start() throws IOException {Scanner scanner = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()){while (true){//1.从控制台读取数据  构造请求System.out.println("请输入要传输的数据");String request = scanner.next();//2.发送请求给服务器PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);printWriter.flush();//3.从服务器读取响应Scanner respScanner = new Scanner(inputStream);String response = respScanner.next();//4.把响应显示在客户端System.out.println(response);}}}public static void main(String[] args) throws IOException {TcpEchoClient tcpEchoClient = new TcpEchoClient("127.0.0.1",9090);tcpEchoClient.start();}}

两种实现方式的区别

为什么实现TCP的Socket时要使用多线程而在UDP的Socket不用呢?

  1. UDP是无连接的,服务器不关心是哪个客户端发送过来的请求都会进行处理。
  2. TCP是有连接的,每次建立连接后服务器都得处理对应客户端的多次请求,此时无法接受其他客户端的连接,不满足实际需求。所以得使用多线程来同时处理多个客户端的请求。

为什么TCP的Socket要关闭,ServerSocket和UDP的Socket不用关闭?

  1. Socket也是一个文件,一个进程能同时打开文件的个数是有限的。因为文件描述符表是有限的。
  2. UDP的Socket不需要建立连接,它在UDP服务器中只有唯一一个对象,不会把文件描述符表占满,随着进程退出会自动释放。
  3. ServerSocket,它在TCP服务器中只有唯一一个对象,不会把文件描述符表占满,随着进程退出会自动释放。
  4. Socket,在TCP的服务器中,每次和一个新的客户端建立连接都要创建一个新的。有可能把文件描述符表占满,就需要释放。

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

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

相关文章

我的架构复盘

1、背景 我目前公司研发中心担任软件研发负责人,研发中心分为3组,总共有30多人。研发中心主要开发各类生产辅助工具,比如巡检、安全教育等系统。系统不对外,只在公司内部使用。 就我个人来说,作为研发负责人&#xf…

SolidWorks2019安装教程(正版)

网盘资源附文末 一.简介 SolidWorks软件是世界上第一个基于Windows开发的三维CAD系统,由于技术创新符合CAD技术的发展潮流和趋势,SolidWorks公司于两年间成为CAD/CAM产业中获利最高的公司。良好的财务状况和用户支持使得SolidWorks每年都有数十乃至数百…

MyBatis入门

MyBatis是一款优秀的持久层框架,用于简化JDBC开发 持久层: 负责将数据保存到数据库的那一层代码 我们会将操作数据库的Java代码作为持久层,而MyBatis就是对jdbc代码进行了封装。 JavaEE三层架构:表现层、业务层、持久层 框架&…

2024最新最全:【Windows10】u盘安装系列教程【附安装包】

安装教程点这里:【Windows10】u盘安装系列教程【附安装包】 1.题外话 什么是如今程序员就业的风口? 对于那些初入计算机行业的新人和刚刚毕业的大学计算机专业学生来说,他们常常面临着就业市场的挑战。这是一个数据时刻: 首先…

【JavaEE】cookie和session

cookie和session cookie什么是 cookieServlet 中使用 cookie相应的API Servlet 中使用 session 相应的 API代码示例: 实现用户登陆Cookie 和 Session 的区别总结 cookie 什么是 cookie cookie的数据从哪里来? 服务器返回给浏览器的 cookie的数据长什么样? cookie 中是键值对…

NI-9219 100 S/s/ch国产化4通道C系列通用多功能模拟输入模块,支持多种传感器

100 S/s/ch,4通道C系列通用模拟输入模块 NI-9219专为多功能测试而设计。NI-9219可用于测量来自多种传感器(如应变计,电阻温度检测器(RTD),热电偶,测压元件和其他有源传感器等)的信号,以及制作1…

基于tpshop开发多商户源码支持手机端+商家+门店 +分销+淘宝数据导入+APP+可视化编辑

tpshop多商户源码,tpshop商城源码,tpshop b2b2c源码-支持手机端商家门店 分销淘宝数据导入APP可视化编辑 tpshop商城源码算是 thinkphp框架里做的比较早 比较好的源码了,写法简明 友好面向程序猿。 这是一款前几年的版本 虽然后台看着好了些,丝毫不影响…

基于VPP的TCP/UDP协议栈加速方案

今天给大家带来英特尔高级软件工程师刘勇在2023英特尔网络技术研讨会上的分享:《基于VPP的TCP/UDP协议栈加速方案》。 随着互联网流量的持续快速增长,作为网络的基本底层组件,TCP/UDP协议栈成为加速网络性能的重点方向。保持和提高带宽增加的…

Flutter 02 基础组件 Container、Text、Image、Icon、ListView

一、Container容器组件: demo1: import package:flutter/material.dart;void main() {runApp(MaterialApp(home: Scaffold(appBar: AppBar(title: const Text("你好Flutter")),body: const MyApp(),),)); }// 容器组件 class MyApp extends St…

树形结构数据展示及返回上一级

11月1日&#xff0c;又是搬砖的一天&#xff0c;让我们红尘作伴&#xff0c;活的潇潇洒洒。。。。。。 html <template><view class"content"><view><input class"sreachTool" v-model"toolValue"/><van-icon name…

gRPC之grpcui界面工具

1、grpcui界面工具 简单的说&#xff0c;就是gRPC中的postman&#xff0c;grpcui官方地址&#xff1a;https://github.com/fullstorydev/grpcui。 1.1 安装 go get -u github.com/fullstorydev/grpcui go install github.com/fullstorydev/grpcui/cmd/grpcuiv1.2.0[rootzsx …

React Hooks的使用

目录 1.React Hooks使用注意事项 1.useState Hook&#xff1a; 2.useEffect Hook&#xff1a; 3.其他常用Hooks&#xff1a; 2.使用React Hooks需要遵循 1.安装React&#xff1a; 2.导入所需的Hooks&#xff1a; 3.使用Hooks创建组件&#xff1a; 4.在应用中使用组件&…