目录

listen()

listen() 函数介绍

listen() 函数的例子

应用层 listen()函数和内核函数之间的关系

accept ()

accept ()函数介绍

accept ()函数的例子

应用层 accept ()函数和内核函数之间的关系


listen()

服务器模式中有 listen() 和 accept() 两个函数,而客户端则不需要这两个函数。
函数 listen() 用来初始化服务器可连接队列,服务器处理客户端连接请求的时候是顺序处理的,同一时间仅能处理一个客户端连接。当多个客户端的连接请求同时到来的时候,服务器并不是同时处理,而是将不能处理的客户端连接请求放到等待队列中,这个队列的长度由 listen() 函数来定义。

listen() 函数介绍

listen() 函数的原型如下,其中的 backlog 表示等待队列的长度。

# include <sys/socket.h>
int listen(int sockfd, int backlog);

当 listen() 函数成功运行时,返回值为0;当运行失败时,它的返回值为﹣1,并且设置 errno 值,错误代码的含义如下所示:

在接受一个连接之前,需要用 listen() 函数来侦听端口,listen() 函数中参数 backlog 的参数表示在 accept() 函数处理之前在等待队列中的客户端的长度,如果超过这个长度,客户端会返回一个 ECONNREFUSED 错误。

listen() 函数仅对类型为 SOCK_STREAM 或者 SOCK_SEQPACKET 的协议有效,例如,如果对一个 SOCK_DGRAM 的协议使用函数 listen(),将会出现错误 errno 应该为值 EOPNOTSUPP,表示此 socket 不支持函数 listen() 操作。大多数系统的设置为20,可以将其设置修改为5或者10,根据系统可承受负载或者应用程序的需求来确定。

listen() 函数的例子

下面是一个 listen() 函数的实例代码,在成功进行 socket() 函数初始化和 bind() 函数端口之后,设置 listen() 函数队列的长度为5。

# define MYPORT 3490 //端口地址
int main (int argc, char *argv[])
{int sockfd;//套接字文件描述符变量struct sockaddr_in my_addr ;//以太网套接字地址结构sockfd = socket(AF_NET, SOCK_STREAM, 0);//初始化 socket if(sockfd == -1)//检查是否正常初始化 socket {perror (" socket ");exit ( EXIT_FAILURE );}my_addr.sin_family = AF_INET ;//地址结构的协议族my_addr.sin_port = htons(MYPORT);//地址结构的端口地址,网络字节序my_addr.sin_addr.s_addr = inet_addr ("192.168.1.150");// IP ,将字符串的 IP 地址转化为网络字节序bzero(my_addr.sin_zero, sizeof(my_addr.sin_zero));//将 my_addr.sin_zero 置0if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) ==- 1)//判断是否绑定成功{perror (" bind ");//打印错误信息exit ( EXIT _ FAILURE );//退出程序}if (listen(sockfd, 5) == -1)//判断是否1isten成功{perror ("1isten");//打印错误信息exit ( EXIT_FAILURE );//退出程序}//接收数据、发送数据和数据的处理过程//关闭套接字*/close ( sockfd );
}

应用层 listen()函数和内核函数之间的关系

应用层 listen() 函数和内核层 listen()函数的关系如图所示:

应用层的 listen()函数对应于系统调用 sys_listen()函数。 sys_listen()函数首先调用 sockfd_lookup_light() 函数获得 sockfd 对应的内核结构 struct socket,查看用户的 backlog 设置值是否过大,如果过大则设置为系统默认最大设置。然后调用抽象的 listen()函数,这里指的是 AF_INET 的 listen()函数和 inet_listen()函数。

inet_listen()函数首先判断是否合法的协议族和协议类型,再更新 socket 的状态值为TCPLISTEN ,然后为客户端的等待队列申请空间并设定侦听端口。

accept ()

当一个客户端的连接请求到达服务器主机侦听的端口时,此时客户端的连接会在队列中等待,直到使用服务器处理接收请求。

函数 accept 成功执行后,会返回一个新的套接字文件描述符来表示客户端的连接,客户端连接的信息可以通过这个新描述符来获得。因此当服务器成功处理客户端的请求连接后,会有两个文件描述符,老的文件描述符表示正在监听的 socket ,新产生的文件描述符表示客户端的连接,函数 send() 和 recv() 通过新的文件描述符进行数据收发。

accept ()函数介绍

accept 函数的原型如下

# include <sys/types.h>
# include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

通过 accept 函数可以得到成功连接客户端的 IP 地址、端口和协议族等信息,这个信息是通过参数 addr 获得的。当 accept 函数返回的时候,会将客户端的信息存储在参数 addr 中。参数 addrlen 表示第2个参数( addr )所指内容的长度,可以使用 sizeof ( struct sockaddr_in )来获得。需要注意的是,在 accept 中 addrlen 参数是一个指针而不是结构, accept 函数将这个指针传给 TCP / IP 协议栈。

accpet() 函数的返回值是新连接的客户端套接字文件描述符,与客户端之间的通信是通过 accept()函数返回的新套接字文件描述符来进行的,而不是通过建立套接字时的文件描述符,这是在程序设计的时候需要注意的地方。如果 accept() 函数发生错误, accept()函数会返回 -1。通过 errno 可以得到错误值,含义在下表中进行介绍。

accept ()函数的例子

下面是一个简单的使用 accept() 函数的例子。这个例子先建立一个流式套接字,然后对套接字进行地址绑定,当绑定成功后,初始化侦听队列的长度,然后等待客户端的连接请求。

# define MYPORT 3490 //端口地址
int main (int argc, char *argv[])
{int sockfd;//套接字文件描述符变量struct sockaddr_in my_addr ;//以太网套接字地址结构sockfd = socket(AF_NET, SOCK_STREAM, 0);//初始化 socket if(sockfd == -1)//检查是否正常初始化 socket {perror (" socket ");exit ( EXIT_FAILURE );}my_addr.sin_family = AF_INET ;//地址结构的协议族my_addr.sin_port = htons(MYPORT);//地址结构的端口地址,网络字节序my_addr.sin_addr.s_addr = INADDR_ANY; // 自动IP地址获取,表示任意的本地IP地址bzero(my_addr.sin_zero, sizeof(my_addr.sin_zero));//将 my_addr.sin_zero 置0//绑定if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) ==- 1)//判断是否绑定成功{perror (" bind ");//打印错误信息exit ( EXIT _ FAILURE );//退出程序}//监听if (listen(sockfd, 5) == -1)//判断是否1isten成功{perror ("1isten");//打印错误信息exit ( EXIT_FAILURE );//退出程序}struct sockaddr_in client_addr; //连接的客户端地址socklen_t addr_length = sizeof(struct sockaddr_in); //地址长度int client_fd = accept(sockfd, &client_addr, &addr_length);if(-1 == addr_length){perror ("accept");//打印错误信息exit ( EXIT_FAILURE );//退出程序}//接收数据、发送数据和数据的处理过程//关闭套接字*/close ( client_fd );close ( sockfd );
}

应用层 accept ()函数和内核函数之间的关系

应用层的 accept()函数和内核层的 accept 函数的关系如图所示:

应用层的 accept()函数对应内核层的 sys_accept()函数系统调用函数。函数 sys_accept()查找文件描述符对应的内核 socket 结构、申请一个用于保存客户端连接的新的内核 socket 结构、获得客户端的地址信息、将连接的客户端地址信息复制到应用层的用户、返回连接客户端 socket 对应的文件描述符。

函数 sys_accept()调用函数 sockfd_lookup_light() 查找到文件描述符对应的内核 socket 结构后,然后会申请一块内存用于保存连接成功的客户端的状态。 socket 结构的一些参数,如类型 type 、操作方式 ops 等会继承服务器原来的值,假如原来服务器的类型为 AF_INET ,则其操作模式仍然是 af_inet.c 文件中的各个函数。然后会查找文件描述符表,获得一个新结构对应的文件描述符。
accept()函数的实际调用根据协议族的不同而不同,即函数指针 sock->ops->accept 要由socket()函数初始化时的协议族而确定。当为 AF_INET 时,此函数指针对应于 af_inet.c 文件中的 inet_accept() 函数。

当客户端连接成功后,内核准备连接的客户端的相关信息,包含客户端的 IP 地址、客户端的端口等信息,协议族的值继承原服务器的值。在成功获得信息之后会调用 move_addr_to_user()函数将信息复制到应用层空间,具体的地址由用户传入的参数来确定。

TCP 网络编程API - listen()、accept()相关推荐

  1. tcp网络编程客户端和服务端及listen和tcp允许最大连接数

    tcp网络编程 tcp网络编程步骤: 由于tcp传输特点是可靠有连接,那么就有 1.客户端向服务端发送连接请求(SYN), 2.服务端接受请求并向客户端发送(SYN+ACK); 3.客户端向服务端回复 ...

  2. C++ tcpip网络编程中listen函数和accept函数详解和区别

    listen函数 摘要:listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程.在TCP服务器编程中listen函数把进程变为一个服务器,并指定 ...

  3. 【计算机网络】Linux环境中的TCP网络编程

    文章目录 前言 一.TCP Socket API 1. socket 2. bind 3. listen 4. accept 5. connect 二.封装TCPSocket 三.服务端的实现 1. ...

  4. TCP网络编程的基本流程

    TCP网络编程的基本流程 对于服务端,通常为以下流程: 调用socket函数创建socket 调用bind函数将socket绑定到某个IP和端口上 调用listen开始监听 当有客户端请求连接上来时, ...

  5. 套接字编程-TCP网络编程

    文章目录 套接字地址结构 通用套接字地址数据结构 以太网协议的套接字地址数据结构 Netlink协议套接字地址结构 TCP网络编程 套接字初始化socket() domain type protoco ...

  6. 网络编程0x04 Listen函数

    网络编程0x04 Listen函数 文章目录 网络编程0x04 Listen函数 1.套接字分类 2. listen函数 3. 监听过程 1.套接字分类 TCP socket分两种: 监听socket ...

  7. 基于数据库及TCP网络编程实现的电子词典

    目录 一.前言 二.项目介绍 三.功能实现 3.1. 用户注册 3.1.1 功能演示 3.1.2 功能函数实现 3.2. 用户登录 3.2.1 功能演示 3.2.2 功能函数实现 3.3. 查询单词 ...

  8. TCP网络编程----C/S模型 (客户端/服务器模型)的代码实现

    TCP网络编程----C/S模型 (客户端/服务器模型)的代码实现 client发送数据到server,server对数据进行提取并根据用户输入的操作符进行两个数的计算,并将计算结果传给client. ...

  9. muduo学习笔记:net部分之实现TCP网络编程库-Acceptor

    前述文章围绕base.net两个模块各种组件,已经形成了初具规模的Reactor事件处理框架.从现在开始,逐步实现一个非阻塞的TCP网络编程库.不同于传统的Reactor,将timers 做成循环中单 ...

最新文章

  1. BCH半月热点事件回顾
  2. syscall 系统调用陷入_trusty系统调用
  3. python小游戏源码-Python小游戏之300行代码实现俄罗斯方块
  4. 调整表格的行高_Word表格无法调整行高?尽然是这个原因,90%的人都可能遇到...
  5. 基于.Net Remoting的项目总结报告
  6. Boost:自定义树的测试程序
  7. go chan 缓存与阻塞
  8. python学习-字符串的基本操作
  9. Android初学第21天
  10. API设计原则(觉得太合适,转发做记录)
  11. java成组链接法的实现_c++磁盘存储空间的管理模拟(UNIX存储管理的成组链接法的设计与实现)...
  12. 23.TCP/IP 详解卷1 --- TCP的保活定时器
  13. 苹果游戏开发教程之如何使用 SpriteKit 和 GameplayKit 制作你的街机手机游戏
  14. CodeMirror用户手册
  15. html怎么设置火狐ie兼容模式,火狐浏览器兼容模式如何设置?火狐浏览器兼容模式设置方法分享...
  16. Boost Serialization 库
  17. Unity学习笔记:Rule Tile、Advance Rule Overide Tile、Rule Override Tile的用法【By Chutianto】
  18. 计算机启动过程中按DEL,电脑开机按del之后如何u盘装系统教程
  19. 许久没有写过原创文章了
  20. 【Android】自己动手做个扫雷游戏

热门文章

  1. Android 日志系统分析(三):logcat
  2. 2010‘FSE-Practical and Effective Symbolic Analysis for Buffer Overflow Detection 利用符号分析方法检测缓冲区溢出
  3. 卷积神经网络(CNN)基础知识
  4. 【Matlab】Java中使用MATLAB作图
  5. PC微信hook基础框架代码编写-->获取微信日志
  6. linux内核学习6:Linux的CPU高速缓存cache和页高速缓存cache,buffer
  7. Java开发高级工程师面试,etcd:一款比Redis更骚的分布式锁的实现方式
  8. 【前端】【vue.js】【参考项目】vue-konva-project
  9. 【智能合约审计】————23、EthLendToken
  10. 游戏革命2023:AIGC拯救游戏厂商