socket

139 阅读7分钟

1.什么是socket?

先看看官方回答:

对网络中不同主机上的应用进程之间进行双向通信(发送发|客户端和接收方|服务端) 的端点的抽象

套接字(socket)是一个抽象层(在应用层和传输层间的一层抽象),应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作(I/O)(例如)。

套接字允许应用程序将插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合

socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。

外观模式,只提供简单的接口,屏蔽内部复杂的实现

自己试着理解一下:

网络协议是一种抽象的东西,只规范了计算机间进行交换时数据流格式

但是在实际进行网络交互时,不光光只有网络协议(数据流格式),还应该有以下步骤

  • 应用程序在内存中组装了一个http的request或response(符合http协议的大字符串|字节流)

    • header、url、query、.....
  • 有了需要发送的数据,需要将数据发送到目的地(需要利用硬件的网卡)

  • 由于不能直接操作硬件网卡(也操作不来),因此通过告诉操作系统告诉他我们要发网络请求

  • 由操作系统完成请求的发送

socket的作用就是操作系统提供的网络传输接口(在应用层和传输层中间) !(socket是以端口为维度,而不是请求维度)(我们通过socket接收到请求后,用线程(从池中获取)处理请求)

我们可以直接在高级语言中使用socket(高级语言封装后的)进行网络编程,也可以使用封装好的包(例如net包,但是底层仍然是调用操作系统socket)进行网络编程

socke发送数据的过程(宏观的)

  • 获得内存中封装好的应用程序请求
  • 根据设置的传输协议,把请求包装
  • 将包装好后的数据复制到网卡上,并且发送数据(发送数据下面详细讲解)

当然socket不光光只可以发送http请求,还可以发起rpc调用....

2.socket通信

2.1通信函数

套接字API最初是作为UNIX操作系统的一部分而开发的,所以套接字API与系统的其他I/O设备集成在一起

当应用程序要为因特网通信而创建一个套接字(socket)时,操作系统就返回一个小整数作为描述符(descriptor)来标识这个套接字(可以对socket(绑定在端口上(一个进程))进行io的读写操作)

  • 服务端初始化Socket

  • 服务端与端口绑定(todo 进程和端口的关系?)\

  • 服务端调用accept阻塞

  • 客户端初始化Socket

  • 客户端连接服务端

  • 客户端写数据(发送)

  • 服务端读数据(接收)

  • 服务端处理结果(每天的工作)(其实服务端也没有对接真实端的流量,会经过lvs,经过Nginx反向代理后,最后落到实际的服务器上)

  • 服务端写数据(发送)

  • 客户端读数据(接收)

2.2socket()函数

  • 作用

    • socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket
    • 后面都需要根据描述符进行一些读写操作(读request,写response)
  • 参数(参数间不可随意组合)

    • protofamily 协议域

      • AF_INET(IPV4)

      • AF_INET6(IPV6)

      • AF_LOCAL(或称AF_UNIX,Unix域socket)

      • AF_ROUTE等等 \

    • type 指定socket类型\

      • SOCK_STREAM\

      • SOCK_DGRAM\

      • SOCK_RAW\

      • SOCK_PACKET\

      • SOCK_SEQPACKET\

    • protocol 应用层协议由应用程序标记\

      • IPPROTO_TCP\

      • IPPTOTO_UDP\

      • IPPROTO_SCTP\

      • IPPROTO_TIPC

2.3bind()函数

  • 作用

    • 绑定特定地址
    • 不使用则随机分配一个
  • 参数

    • sockfd socket描述字,它是通过socket()函数创建

    • addr sockfd的协议地址\

    • addrlen 地址的长度(IP地址+端口号)\

网络字节序与主机字节序
主机字节序就是我们平常说的大端和小端模式:不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序。
引用标准的Big-Endian和Little-Endian的定义如下:
a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
网络字节序:4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。
这种传输次序称作大端字节序。由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。
字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序,一个字节的数据没有顺序的问题了。
所以:在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。
由于这个问题曾引发过血案!公司项目代码中由于存在这个问题,导致了很多莫名其妙的问题,所以请谨记对主机字节序不要做任何假定,
务必将其转化为网络字节序再赋给socket。\

2.4listen()、connect()函数

  • listen() 

    • 作用:服务端使用,被动等待请求

    • 参数

      • socket描述字\

      • 相应socket可以排队的最大连接个数\

  • connect() 

    • 作用:客户端使用,主动发起请求(浏览器其实也是服务端程序 socket收发请求+静态资源渲染)

    • 参数

      • 客户端的socket描述字\

      • 服务器的socket地址\

      • socket地址的长度\

2.5accept()函数

  • 作用:服务端建立连接,可以进行网络IO,类似普通文件的IO

  • 参数

    • \

2.6read()、write()等函数

  • 数据的读写操作(客户端和服务端)

2.7close函数

  • 完成了读写操作就要关闭相应的socket(类似的文件的读写操作)\

2.8socket与三次握手与四次挥手(当协议为tcp时)

\

3.补充

3.1 http与rpc的对比

http curl与rpc调用的区别:

http curlrpc调用
底层实现封装好请求数据后,通过socket发送数据,通过socket监听数据
序列化方式使用http协议发送的是一个大字符串接收的也是一个大字符有thrift协议pb协议.....
入参不确定确定
出参不确定,需要一层层解析json串确定,可以在语言中通过对象使用
序列化效率
发送包大小
特点可以基于rpc框架,进行限流熔断等服务治理

3.2进程和端口关系

端口是固定的,只能和一个线程|线程号绑定

查询端口号(知道端口号):lsof -i:端口号 可以查询对应的进程号

查询进程号(不知道端口号):ps aux|grep common

杀死进程:kill -9 pid

3.3文件读写后为什么要close(socket也是一种文件)

  • 作用:

    • 终止指定文件描述符与对应文件之间的关联
    • 并释放该文件描述符,即该文件描述符可被重新使用
  • 文件描述符

    • 非负整数内核(kernel)利用文件描述符(file descriptor)来访问文件\

    • 不同的文件可以被不同的进程打开

    • 打开现存文件或新建文件时,内核会返回一个文件描述符\

    • 读写文件也需要使用文件描述符来指定待读写的文件

  • 举个栗子

    • 标准输入(standard input)的文件描述符是 0\

    • 标准输出(standard output)是 1\

    • 标准错误(standard error)是 2\

  • 文件

    • FILE结构包括一个缓冲区和一个文件描述符\

    • io的文件对象,内存可能包含一个内存buffer(猜的,有待考证)

4.资料

  1. baike.baidu.com/item/%E5%A5…
  2. zhuanlan.zhihu.com/p/260139078
  3. www.zhihu.com/question/20…
  4. www.zhihu.com/question/39…
  5. blog.csdn.net/tianlongtc/…
  6. www.jianshu.com/p/c40ba165c…
  7. baike.baidu.com/item/%E6%96…