• 【五】Socket函数详解


    ❤️ 专栏简介 :网络通信和Socket编程是Linux C/C++服务器开发的基础。本专栏从最基础的内容开始学习网络通信和socket编程的相关内容,循序渐进的掌握网络通信的和socket编程的相关知识。主要内容包括网络通信与socket编程概述、socket通信模型、套接字概述、socket通信交互流程以及Socket通信中各个函数的实现以及功能等。

    ☀️ 专栏适用人群 :适用于具备基础 Linux 知识的并想从零开始学习网络通信和Socket编程初学者;以及想学习Linux上c/c++服务器开发的朋友们。

    🌙专栏特点:通俗易懂、图文并茂、非常详细;

    🌴 专栏说明 :如果文章知识点有错误的地方,欢迎大家随时在文章下面评论,我会第一时间改正。让我们一起学习,一起进步。

    🍄 专栏地址:https://blog.csdn.net/anchenliang_1002/category_11919076.html

    本节我们来详细的对socket的函数进行学习,主要包括函数关系图socket函数bind函数listen函数accept函数connect函数等

    一、函数关系图

    socket中各个函数的关系图如下所示:

    在这里插入图片描述
    经过三次握手才能确立连接,才能正常的收发数据;即在客户端,connect()后,经过三次握手,成功,才会读写数据;同样的,在服务端,listen()后,经过三次握手后,调用accept()接受连接,之后读写数据。

    二、Socket函数

    1.1 函数功能

    socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调用出错则返回-1。对于IPv4,domain参数指定为AF_INET。对于TCP协议,type参数指定为SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定为SOCK_DGRAM,表示面向数据报的传输协议。protocol参数一般指定为0即可。

    1.2 头文件

    #include  
    #include 
    
    • 1
    • 2

    1.3 函数定义

    int socket(int domain, int type, int protocol);
    
    • 1

    domain
    AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址
    AF_INET6 与上面类似,不过是来用IPv6的地址
    AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用
    type:
    SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
    SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
    SOCK_SEQPACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。
    SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
    SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序
    protocol:
    传0 表示使用默认协议。

    1.4 返回值

    成功:返回指向新创建的socket的文件描述符;
    失败:返回-1,设置errno

    三、bind函数

    1.1 函数功能

    bind()的作用是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号

    详细解释:

    服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后就可以向服务器发起连接,因此服务器需要调用bind绑定一个固定的网络地址和端口号。

    bind()的作用是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号。前面讲过,struct sockaddr *是一个通用指针类型,addr参数实际上可以接受多种协议的sockaddr结构体,而它们的长度各不相同,所以需要第三个参数addrlen指定结构体的长度。

    1.2 头文件

    #include  
    #include 
    
    • 1
    • 2

    1.3 函数定义

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    
    • 1

    sockfd
    通过socket函数,返回的文件描述符
    addr:
    构造出IP地址加端口号
    addrlen:
    sizeof(addr)长度

    1.4 返回值

    成功:返回0;
    失败:返回-1,设置errno

    四、listen函数

    1.1 函数功能

    bind函数的作用是将套接字绑定一个IP地址和端口号。

    详细解释:
    典型的服务器程序可以同时服务于多个客户端,当有客户端发起连接时,服务器调用的accept()返回并接受这个连接,如果有大量的客户端发起连接而服务器来不及处理,尚未accept的客户端就处于连接等待状态,listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态,如果接收到更多的连接请求就忽略。

    1.2 头文件

    #include  
    #include 
    
    • 1
    • 2

    1.3 函数定义

    int listen(int sockfd, int backlog);
    
    • 1

    sockfd:
    socket文件描述符
    backlog:
    在Linux 系统中,它是指排队等待建立3次握手队列长度

    查看系统默认backlog

    cat /proc/sys/net/ipv4/tcp_max_syn_backlog
    
    • 1

    改变 系统限制的backlog 大小

    vim /etc/sysctl.conf
    
    • 1

    最后添加

    net.core.somaxconn = 1024
    net.ipv4.tcp_max_syn_backlog = 1024
    
    • 1
    • 2

    保存,然后执行

    sysctl -p
    
    • 1

    1.4 返回值

    成功:返回0;
    失败:返回-1,设置errno

    五、accept函数

    1.1 函数功能

    accept()函数的功能是接收、接受一个客户端的连接。

    详细解释:
    三次握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。addr是一个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是一个传入传出参数(value-result argument),传入的是调用者提供的缓冲区addr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)。如果给addr参数传NULL,表示不关心客户端的地址。

    通俗一点就是说,调用accept函数需要传入三个参数,第一个参数是要接收的socket;第二个参数是我们创建一个存放客户端ip和端口的结构体,并传进去,accept执行后传出该参数,里面就写好了接收到的客户端请求的ip和端口;第三个参数传入的是最大缓冲区的大小,执行完accept后返回的是实际使用的大小。

    1.2 头文件

    #include  
    #include 
    
    • 1
    • 2

    1.3 函数定义

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    
    • 1

    sockdf:
    socket文件描述符
    addr:
    传出参数,返回链接客户端地址信息,含IP地址和端口号
    addrlen:
    传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小

    1.4 返回值

    成功:返回一个新的socket文件描述符,用于和客户端通信;
    失败:返回-1,设置errno

    六、connect函数

    1.1 函数功能

    connect()函数的功能连接服务端。

    详细解释:

    客户端需要调用connect()连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址。

    1.2 头文件

    #include  
    #include 
    
    • 1
    • 2

    1.3 函数定义

    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    
    • 1

    sockdf:
    socket文件描述符
    addr:
    传入参数,指定服务器端地址信息,含IP地址和端口号
    addrlen:
    传入参数,传入sizeof(addr)大小

    1.4 返回值

    成功:返回0;
    失败:返回-1,设置errno

  • 相关阅读:
    后端 ---- 面试题 / 笔试题
    堆-----数据结构
    【MySQL】多表查询
    【owt】vs2022 + v141 : 查看WINDOWSSDKDIR
    设计模式-观察者模式在Java中的使用示例-环境监测系统
    HashSet的存储机制
    数据结构-----红黑树简介
    【数据结构】测试3 栈和队列
    Redis启动命令和5种数据leix
    halcon程序如何导出C#文件
  • 原文地址:https://blog.csdn.net/AnChenliang_1002/article/details/126394935