• 【网络编程】socket、端口、进程的关系


    文章目录

    1. Socket 的概念

    端口是TCP/IP协议中的概念,描述的是TCP协议上层的应用(FTP,HTTP,SMTP…),在操作系统中,可以理解为基于TCP的系统服务或者说系统进程!如下图,FTP就需要占用特定的TCP端口。TCP/IP 协议栈的实现在系统层,HTTP,FTP 在应用层,因此每个端口都要关联到一个进程上!

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yfDYOTG1-1661549467553)(http://www.myexception.org/img/2015/05/26/152450685.jpg)]

    而 socket 呢,是网络编程中的概念,是 TCP/IP 协议栈在操作系统中的代理,为应用层提供服务。这里的程序C,可以是FTP client,也可以是 Web client, 程序 S 则对应 FTP Server 和 Web Server。

    在这里插入图片描述
    对于操作系统来说,无论是 client 还是 server,都属于应用层的软件,要通过 socket 与内核中的网络协议栈进行交互。
    socket 是核心,是枢纽,是进程与网络建立关系的必经之路!

    2. 内核是如何将数据包转发至 socket 的呢?

    网络数据首先到达网卡,然后进入内核,由网络协议栈去处理,那么内核是如何进行数据分发的呢?它怎么知道该如何把数据交给特定的用户进程呢?

    这时,就需要 socket 发挥作用了!

    socket 中存储了特定的四元组: 源ip+port,目的ip+port;

    TCP Client :

    1. 源 ip+port ,socket 为 [src ip, src port) <=> (*, *)] ;
    2. Connect 到目的 ip+port,socket 变为 [src ip, src port) <=> (dst ip, dst port)];
    3. 通过 Socket 与 TCP Server 进行通信。

    Client 端,一个连接会占用一个系统端口。

    TCP Server:

    1. Accept 返回的 socket 为 [src ip, src port) <=> (dst ip, dst port)];每一个连接都对应一个 socket id。

    Server 端,所有连接共享同一个端口。

    当系统接收 TCP 网络数据时,根据端口定位到特定的进程,然后进程根据 socket id 区分来自不同 client 的数据。系统中所有 socket 中的四元组信息,必定唯一,不可能重复!

    这里写图片描述

    3. 进程与 socket

    每个进程,在内核中都有一个表,保存了该进程申请并占用的所有 socket 描述符,在进程看来,socket 其实跟文件也没有什么不同,只不过通过描述符获得的对象不同而已,接口对应的系统调用也不同。

    在这里插入图片描述

    那么进程跟socket是一一对应的吗?

    其实不然,socket是一种资源,就像文件一样,一个进程打开了,另一个进程也可以用,只不过socket比较特殊而已。

    理论上,能够通过 sendmsg 将 socket 描述符传递给其他进程,这样其他进程就可以调用该描述符的接口了。这种场景确实不怎么会用到,也没有进行实际验证。

    当然,父子进程间,还有线程间,进行 socket 的共享,是比较常见的。

    4. 进程与端口

    进程与端口,其实并没有什么直接或必然的关系,关键还是socket!

    wireshark 抓包查看tcp协议数据包详情:

    server:

    #-*- coding:utf-8 -*-
    
    from SocketServer import TCPServer, BaseRequestHandler
    import traceback
    
    class MyBaseRequestHandlerr(BaseRequestHandler):
        """
        #从BaseRequestHandler继承,并重写handle方法
        """
        def handle(self):
            #循环监听(读取)来自客户端的数据
            while True:
                #当客户端主动断开连接时,self.recv(1024)会抛出异常
                try:
                    #一次读取1024字节,并去除两端的空白字符(包括空格,TAB,
    ,
    )
                    data = self.request.recv(1024).strip()
                    
                    #self.client_address是客户端的连接(host, port)的元组
                    print "receive from (%r):%r" % (self.client_address, data)
                    
                    #转换成大写后写回(发生到)客户端
                    self.request.sendall(data.upper())
                except:
                    traceback.print_exc()
                    break
    
    if __name__ == "__main__":
        #telnet 127.0.0.1 9999
        host = ""       #主机名,可以是ip,像localhost的主机名,或""
        port = 9999     #端口
        addr = (host, port)
        
        #购置TCPServer对象,
        server = TCPServer(addr, MyBaseRequestHandlerr)
        
        #启动服务监听
        server.serve_forever()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    client:

    import socket
    
    s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
    s.connect(( "xxx.xxx.xx.xx", 9999))
    s.send("Hello socket!")
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这里写图片描述

    总结

    socket 的本质是一种资源,它包含了端到端的四元组信息,用来标识数据包的归属。因此,尽管 tcp 协议的端口号只有 65535 个,但是进程可拥有的 socket 数据却不限于此(受限于进程最大文件描述符数据);

  • 相关阅读:
    git push 总是需要输入密码或者个人访问令牌personal access token解决方案
    【代码随想录】二刷-双指针法
    求余数联系和赋值运算
    [SpringBoot] 父子项目搭建,过滤多模块发布到私仓
    网络安全笔记 -- 文件上传2(内容逻辑数组绕过、中间件漏洞绕过、WAF绕过)
    设计模式-代理模式
    leetcode134.加油站 贪心法求解 (c++版本)
    Hive 视图和索引
    电脑出现丢失msvcp71.dll的解决方法_常见msvcp71.dll解决方法
    小程序开发流程
  • 原文地址:https://blog.csdn.net/m0_67402236/article/details/126553388