【网络原理】网络编程Socket套接字基础知识汇总
创始人
2024-04-02 20:46:31
0

目录

1.网络初始:

2.网络编程:

3.UDP数据报套接字:

4.TCP流套接字:


1.网络初始:

  1. 局域网(LAN)广域网(WAN)
  2. IP地址用于定位主机的网络地址。端口号可以标识主机中发送数据接收数据的进程(用于定位主机中的进程)。一个端口只能被一个进程绑定(通常情况),但是一个进程可以绑定多个端口号。
  3. 协议是俩个人的事情,只有双方都了解并且遵守才有意义!
  4. 协议分层,上层协议调用下层协议,下层协议给上层协议提供服务,相邻的层是可以相互交互的,但是不能跨层级。
  5. TCP/IP五层网络模型和封装,
    假设主机A给主机B发了个helloworld
    主机A发送的过程一.应用层应用程序会把输入的helloworld构造成约定好的应用层协议的报文应用程序就会把这个应用数据报文,交给传输层协议传输层是操作系统内核实现的,操作系统提供了一些API给应用程序,这些API叫做socket api,代码调用这些api就可以把应用层的数据交给传输层(交给了操作系统内核)二.传输层传输层这里有很多协议,最典型的就是TCP协议,此处以TCP为例TCP协议要在之前的基础上,加上个TCP的协议报头这个TCP报头里面最重要的就是源端口和目的端口!传输层继续将这个数据交给网络层进行处理三.网络层网络层中最典型的就是IP协议IP协议把整个TCP数据看成整体,作为载荷部分,在前头加上IP协议报头IP协议报头里面有很多信息,最关键的就是源IP和目的IP构造好IP数据报之后,IP协议继续把整个数据交给数据链路层四.数据链路层数据链路层的协议有很多,最典型的就是以太网以太网这个歌协议既管数据链路层,又管物理层以太网数据帧将IP数据报的前头加上帧头(源mac地址和目的mac地址),后头加上帧尾(校验和)五.物理层到达物理层的数据已经组织好了就可以通过物理层设备(网卡)把上述数据的二进制bit流转换成光信号或电信号来传输
  6. 分用就是封装的逆过程,封装是打包快递,而分用就是拆开快递。
  7. 网络中的细节太多了,如果一个协议搞定,那这个协议就会非常的复杂。因此就需要拆分,拆分的多了,又要分层。拆分之后,一个协议负责一件事情,这样才把这些关键信息放到了不同的协议报头中。

2.网络编程:

  1. 网络编程指的是网络上的主机,通过不同的进程,以编程的方式实现网络通信。网络编程主要是针对应用层。
  2. 网络编程套接字,就是研究如何写代码完成网络编程。socket api是一切网络编程的基础。
  3. socket套接字是操作系统给应用程序提供的API,描述的是应用层和传输层的交互,其实socket api就是传输层给应用层提供的。
  4. API就是一组类和方法。应用程序就可以通过socket api来进行网络编程(操作网卡)。
  5. 网络传输层中又很多种协议,最主要的就是TCP和UDP。因此操作系统就提供了俩个不同的版本的API。
  6. 传输层中TCP和UDP的区别
    TCPUDP
    有连接无连接
    可靠传输不可靠传输
    面向字节流面向数据报
    全双工全双工
  7. TCP和文件操作一样是基于“流”的,而UDP则是以“数据报”为基本单位。全双工是一个通道,双向通信;半双工是一个通道,单向通信。网络通信一般都是全双工的。有连接就相当于打电话,必须通信的双方建立好了连接才可以正常打电话;而无连接相当于发短信,直接就可以发送过去。

3.UDP数据报套接字:

  1. DatagramSocketDatagramPacket是UDP socket需要掌握的类。
  2. DatagramSocket,是网卡的代言人,借助这个类来读写网卡。通过网卡发送数据就是写文件,接收数据就是读文件。
    方法签名说明
    DatagramSocket()一般用于客户端,创建一个UDP数据报套接字的socket,绑定到随机一个端口
    DatagramSocket(int port)一般用于服务器,创建一个UDP数据报套接字的socket,绑定到指定端口
    void receive(DatagramPacket p )接收数据报,没有收到会阻塞等待
    void send(DatagramPacket p )发送数据报,不会阻塞等待
    void close()关闭数据报套接字
  3. socket本质上是一个文件。socket对应到网卡这个硬件设备,操作系统也是把网卡当作文件来管理。通过网卡发送数据,就是写文件;通过网卡接收数据,就是读文件。
  4. DatagramPacket,代表一个UDP数据包,是一次发送/接受的基本单位;发送和接收的是DatagramPacket。
    方法签名说明
    DatagramPacket(byte[ ] b,int length)构造一个DatagramPacket用来接收数据报,接收的数据保存在字节数组里
    DatagramPacket(byte[ ] b,int offset,int length,address)构造一个DatagramPacket用来发送数据报,发送的数据为字节数组的指定长度。address为指定目的主机的IP和端口号。
    getAddress()从接收的数据报中获取发送端主机IP地址;或从发送的数据报中获取接收端主机IP地址
    int getPort()从接收的数据报中获取发送端主机端口号;或从发送的数据报中获取接收端主机端口号
    byte[ ] getData()获取数据报中的数据
  5. UDP实现回显服务器(服务器部分)
    //UDP版本:回显服务器的服务器部分public class UdpEchoServer {private DatagramSocket socket = null;//参数的端口表示服务器要绑定的端口//不需要指定IP,就是本机的IPpublic UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}//启动服务器public void start() throws IOException {System.out.println("服务器启动了!!!");while(true){//1.读取请求并且解析//socket的receive操作需要一个空的requestPacket,receive方法的参数是一个输出型参数//将空的DatagramPacket对象交给receive,在receive里面负责把从网卡读到的数据填充到这个对象中DatagramPacket requestPacket = new DatagramPacket(new byte[1024],1024);//要给DatagramPacket申请内存空间socket.receive(requestPacket);//将DatagramPacket转换成字符串    getData()是获取数据报中的数据,返回一个byte[]String request = new String(requestPacket.getData(),0, requestPacket.getLength());//2.根据请求计算响应String response = process(request);//3.把响应返回给客户端//发送DatagramPacket对象需要指定IP地址和端口号DatagramPacket responsePacket = new DatagramPacket(    //getSocketAddress就是得到客户端的IP和端口号response.getBytes(),response.getBytes().length, requestPacket.getSocketAddress());socket.send(responsePacket);//4.打印一个日志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 {UdpEchoServer server = new UdpEchoServer(1025);server.start();}
    }

  6. UDP实现回显服务器(客户端部分)
    //UDP版本:回显服务器的客户端部分public class UdpEchoClient {private DatagramSocket socket = null;private String serverIP;private int serverPort;//服务器的IP一般不用写,就是本机的IP//需要传服务器的IP和服务器的端口public UdpEchoClient(String serverIp,int serverPort) throws SocketException {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.print("-> ");String request = scanner.nextLine();//2.构造一个UDP请求,发送给服务器DatagramPacket requestPacket = new DatagramPacket(//request.getBytes().length这里的length单位是字节//request.length()这里的length()单位是字符,不可以改成这样request.getBytes(),request.getBytes().length, InetAddress.getByName(this.serverIP),this.serverPort);socket.send(requestPacket);//3.从服务器接收响应,并且转成字符串DatagramPacket responsePacket = new DatagramPacket(new byte[1024],1024);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 {//IP是某某食堂,端口号是某某窗口UdpEchoClient client = new UdpEchoClient("127.0.0.1",1025);client.start();}
    }
    

  7. DatagramPacket的三种构造方法
  8. 为什么服务器需要指定端口,而客户端不用指定端口???答:服务器指定端口目的就是方便客户端找到服务器在哪,而客户端不指定端口因为操作系统会分配一个空闲的端口,如果手动指定了万一用户电脑上的其他程序占用了这个端口,就会导致程序无法正确运行了。
  9. 对于服务器来说,读取请求并且解析、根据请求计算响应和把响应写回到客户端执行的速度是极快的。如果有多个客户端同时发来请求,服务器也是可以响应的,但是本质上这三个请求的串行处理的!
  10. 当前俩个程序放在同一个主机上是通过127.0.0.1这个IP来通信的;也可以把俩个程序放在不同的主机上也是可以通信的,但是如果放在不同的主机上,要确保服务器的地址是可以访问到的!

4.TCP流套接字:

  1. ServerSocketSocket是TCP流套接字需要掌握的俩个类。
  2. ServerSocket是创建TCP服务器的api,给服务器使用的类,用来监听端口。
    方法签名说明
    ServerSocket(int port)创建一个服务端流套接字Socket,并且绑定指定端口
    Socket accept()有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待
    void close()关闭此套接字
  3. Socket既会给服务器使用也会给客户端使用,用来传输数据。
    方法签名说明
    Socket(String host,int port)创建一个客户端流套接字Socket,并且尝试和对应IP的主机上对应端口的进程建立连接
    InetAddress getInetAddress()返回套接字所连接的地址,获取IP和端口
    int getPort()返回套接字所连接的端口
    InputStream  getInputStream()返回此套接字的输入流
    OutputStream getOutputStream()返回此套接字的输出流
  4. TCP实现回显服务器(服务器部分)
    //TCP版本:回显服务器服务器部分public class TcpEchoServer {private ServerSocket listenSocket = null;public TcpEchoServer(int port) throws IOException {listenSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器启动!!");//使用线程池ExecutorService service = Executors.newCachedThreadPool();while(true) {//1.先调用acceptSocket clientSocket = listenSocket.accept();//2.再来处理这个连接,这里应该使用多线程,每个客户端连上来都分配一个新的线程负责处理//使用多线程确实可以解决问题,但是会频繁的创建和销毁线程!
    //            Thread t = new Thread(()->{
    //                try {
    //                    processConnection(clientSocket);
    //                } catch (IOException e) {
    //                    throw new RuntimeException(e);
    //                }
    //            });
    //            t.start();service.submit(new Runnable() {@Overridepublic void run() {try {processConnection(clientSocket);} catch (IOException e) {e.printStackTrace();}}});}}private void processConnection(Socket clientSocket) throws IOException {System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());//处理客户端的请求//clientSocket代表的是服务器的网卡,inputStream代表从网卡读数据也就相当于从客户端读取数据try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()){while(true){//1.读取请求并且解析Scanner scanner = new Scanner(inputStream);if(!scanner.hasNext()){System.out.printf("[%s:%d] 客户端下线!\n",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("[%s:%d] req: %s; resp: %s\n",clientSocket.getInetAddress().toString(),clientSocket.getPort(),request,response);}} catch (IOException e) {e.printStackTrace();}finally {//为什么这个clientSocket要关闭文件,前面的listenSocket和UDP程序中的socket都不需要关闭文件呢?clientSocket.close();}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9090);server.start();}
    }

  5. TCP实现回显服务器(客户端部分)
    //TCP版本:回显服务器客户端部分public class TcpEchoClient {private Socket socket = null;public TcpEchoClient(String serverIp, int serverPort) throws IOException {socket = new Socket(serverIp, serverPort);}public void start() {Scanner scanner = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while (true) {//1.从控制台读取数据System.out.print("-> ");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);}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpEchoClient server = new TcpEchoClient("127.0.0.1",9090);server.start();}}

  6. TCP实现回显服务器的服务器代码部分,如果使用1的话,就不能让多个客户端同时使用服务器;如果使用2,频繁的创建和销毁代价较大,所以推荐使用线程池!
  7. TCP实现回显服务器的服务器代码中需要close文件!
  8. 启动服务器,如果没有客户端建立连接,服务器就会阻塞等待。如果有一个客户端过来了,此时就会显示客户端已上线并且向下执行代码。如果再有一个客户端也过来了,使用上述的方案1那么不会显示这个客户端已上线。
  9. TCP中的长短连接。TCP发送数据时需要先建立连接,什么时候关闭连接就决定是短连接还是长连接。短连接:每次收到数据并返回响应后,都关闭连接,也就是短连接只能一次收发数据,TCP每个连接只处理一个客户端请求能够保证快速调用到accept。长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,也就是长连接可以多次收发数据,TCP建立连接之后,要处理客户端的多次请求才导致无法快速调用accept。


如果对您有帮助的话,

不要忘记点赞+关注哦,蟹蟹

如果对您有帮助的话,

不要忘记点赞+关注哦,蟹蟹

如果对您有帮助的话,

不要忘记点赞+关注哦,蟹蟹

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...