Linux C中的listen函数及其应用 (linux c listen函数)

Linux是一个广泛应用于服务器领域的操作系统,C语言则是Linux中最为重要的编程语言之一。在Linux C中,listen是一个十分重要的系统函数,它被用于提供服务端的网络通信功能。本文将深入探讨Linux C中的listen函数,分析其应用及重要性。

一、listen函数的概述

listen函数是Linux C中用于初始化服务端套接字,使其处于侦听状态的函数,主要包括两个输入参数:sockfd和backlog。

sockfd表示需要进行监听的套接字,它的值由前面的socket函数返回。backlog则表示内核为相应套接字管理的连接请求队列的更大长度,一般该值会被系统限制为128,但也可以通过修改系统配置文件来更改其值。

listen函数的定义如下:

int listen(int sockfd, int backlog);

其中,sockfd为一个已建立连接的套接字,backlog为待连接队列的更大长度。 特别地,参数backlog为0时,服务端套接字进入阻塞模式,即accept函数一定会等待直到有客户端连接请求到来。

函数的返回值通常有两种情况下会返回-1,分别为:

● 参数无效。例如,sock错误或者backlog值为负数。

● 监听失败。例如,由于操作系统网络限制或者系统资源不足导致监听失败。

二、客户端和服务端间的通信

客户端和服务端间的通信基于TCP/IP协议,它们之间的通信过程如下:

客户端向服务端发起请求(比如打开了一个网页) -> 服务端收到请求,返回响应(比如返回网页数据) -> 客户端收到响应,展示结果(比如浏览网页)。

如上所示,服务端的角色是接收客户端的请求,进行处理,然后返回响应。在网络编程中,服务端需要采用若干种技术来实现这种角色。其中,listen是服务端实现的之一步。只有经过listen函数初始化,服务端套接字才能够接收连接请求。

下面我们将具体介绍listen函数在网络编程中所扮演的角色。

三、listen 函数的应用

listen函数的应用体现在如下三个方面:

1.监听指定端口,等待客户端的连接请求

listen函数将服务端套接字从“封闭状态”切换到“侦听状态”,即将该套接字从不接受连接的状态变为接受连接状态。

一旦listen函数被调用,该函数会一直等待客户端的连接请求,直到有连接请求进入套接字,或者listen函数返回错误。当客户端有连接请求过来时,内核会将客户端的请求放到服务端套接字的“待连接队列”中,等待服务端调用accept函数获取。

2.通过accept函数接收来自客户端的连接请求

accept是Linux C中用于从服务端套接字的“待连接队列”中获取客户端请求的函数,它返回已连接的套接字,该套接字可以用于后续的正常通信。在使用accept函数的时候,需要注意下面两个问题:

● accept函数只能获取“待连接队列”中的队首客户端请求。如果任务队列中有多个客户端同时发送连接请求,服务端只能处理队首的请求。

● accept函数是一个阻塞函数,调用它时,如果队列中没有客户端连接的请求,accept函数会一直阻塞,直到有客户端发来连接请求。

3.对套接字进行非阻塞处理

有时候,服务端套接字接收到大量连接请求,但是处理速度跟不上连接的速度,并造成套接字的阻塞。

此时可以通过将套接字设置为“非阻塞模式”来解决这个问题。服务端接收到连接请求后,立即将它塞入等待队列,然后就返回,等待accept函数处理该请求。当服务端处理完前一个连接请求后,accept函数又会获取下一个连接请求,这样就实现了非阻塞处理。

四、

本文对进行了深入的研究和。通过对listen函数的了解,我们不仅能够更好地理解网络编程的流程和技术,还能够为我们编写高质量的服务器端程序提供重要的参考依据。对于任何一个网络编程工程师来说,熟练掌握listen函数的应用是非常重要的。

相关问题拓展阅读:

如何实现在Linux下创建服务程序

Linux系统能提供强大可靠的网络服务,并有管理程序对服务进行管理。例如我们熟悉的Web、FTP和电子邮件等,它们既可以单独运行,也可以被守护进程inetd调用,而且运行得都非常好。但我们不能仅停留在赞叹中,下面就给出两个服务程序程序和一个客户程序的例子,介绍服务程序和客户程序之间是如何沟通的。另外还要编辑配置一些文件,让服务程序也能接受服务管理程序管理。

这两个服务程序功能相同,但一个是独立服务程序,另一个是被inetd调用的服务程序。这是TCP/IP网络服务的两大类,这里将两个程序放在一起是为了比较程序结构和运行方式。两服务程序都在Red Hat Linux 7.1和TurboLinux 7.0上调试通过。

独立服务器

TCP和UDP是两大TCP/IP数据传输方式,套接口是建立服务器客户机连接的机制,首先介绍它们建立通信联系的过程,然后给出一个TCP服务程序例子。

1.TCP套接口通信方式

对于TCP服务器端,服务程序首先调用建立套接口的函数socket(),然后调用绑定服务IP地址和协议端口号函数bind()。绑定成功后调用被动监听函数listen()等待客户连接,还要调用获取连接请求函数accept(),并一直阻塞到客户连接请求的到达,这个函数获取客户机IP地址和协议端口号。

对于TCP客户端,客户程序启动后后调用建立套接口函数socket(),然后调用连接函数connect(),此函数与服务器通过三次握手建立连接。

服务器和客户机建立连接后,就可以使用读函数read()和写函数write()收发数据了。数据交换完成后便各自调用关闭套接口函数close()删除套接口。TCP套接口通信方式见图1所示。

图1 TCP套接口通信方式

2.UDP套接口通信方式

UDP程序与TCP的区别是无需建立连接。服务器首先启动,然后等待用户请求。客户机启动后便直接向服务器请求服务,服务器接到请求后给出应答。

对于UDP服务器端,服务程序首先调用套接口函数socket(),然后调用绑定IP地址和协议端口号函数bind()。之后调用函数recvfrom()接收客户数据,调用sendto()向客户发送数据。

对于UDP客户端,客户机程序启动后调用套接口函数socket(),然后调用sendto()向服务器发送数据,调用recvfrom()接收服务器数据。

双方数据交换成功后,各自调用关闭套接口函数close()关闭套接口。UDP套接口通信方式见图2所示。

图2 UDP套接口通信方式

下面给出独立服务程序的例子。这个程序虽然简单,但是与复杂程序有着相同的结构。

//程序名:server.c

//功能:服务器从客户机读入一个字符,并将排在此字符后面的字符回送客户机

//服务器端口:9000

#include “sys/types.h”

#include “sys/socket.h”

#include “stdio.h”

#include “netinet/in.h”

#include “arpa/inet.h”

#include “unistd.h”

int main()

{

int pid; //用于存放fork()执行结果

int server_sockfd,client_sockfd; //用于服务器和客户机套接口描述符

int bind_flag,listen_flag; //用于存放bind()和listen()执行结果

int server_address_length,client_address_length; //作为服务器客户机地址长变量

struct sockaddr_in server_address; //作为服务器地址结构变量(含地址和端口)

struct sockaddr_in client_address; //作为客户机地址结构变量(含地址和端口)

if((pid=fork())!=0) //用fork()产生新进程

exit(0) ;

setsid() ; //以子进程开始下面的程序

函数socket(),创建一个套接口,成功则返回套接口描述符。

server_sockfd=socket(AF_INET,SOCK_STREAM,0);

if(server_sockfd

{

printf(“socket error /n”);

exit(1);

}

server_address.sin_family=AF_INET;

函数htonl()用于将32位主机字节顺序转换为网络字节顺序,其中参数INADDR_ANY表示任何IP地址。

server_address.sin_addr.s_addr=htonl(INADDR_ANY);

函数htons()用于将16位主机字节顺序转换为网络字节顺序,其中的参数是绑定的端口号,读者可根据环境自行改动,目的是不与其它服务端口冲突。

server_address.sin_port=htons(9000);

server_address_length=sizeof(server_address);

函数bind()用于绑定本地地址和服务端口号,若调用成功返回值为0。

bind_flag=bind(server_sockfd,/

(struct sockaddr *)&server_address,/

server_address_length);

if(bind_flag

{

printf(“bind error /n”);

exit(1);

}

函数listen(),指明服务器的队列长度,被动等待客户连接,调用成功返回值为0。

listen_flag=listen(server_sockfd,5);

if(listen_flag

{

printf(“listen error /n”);

exit(1);

}

while(1)

{

char ch;

函数accept()等待和获取用户请求,为每个新连接请求创建一个新的套接口,调用成功返回新套接口描述符。

client_sockfd=accept(server_sockfd,/

(struct sockaddr *)&client_address,/

&client_address_length);

函数read()和write()用于在服务器和客户机之间传送数据,调用成功返回读和写的字节数。

函数close(),用于程序使用完一个套接口后关闭套接口,调用成功返回值0。其中的参数为accept()创建的套接口的描述符client_sockfd。

read(client_sockfd,&ch,1);

printf(“cli_ch=%c”,ch);

ch++;

write(client_sockfd,&ch,1);

close(client_sockfd);

}

}

程序完成后就可以使用命令进行编译。在命令行中输入“gcc -o server server.c”,将server.c编译成可执行程序server,这时便可用客户程序进行测试。在命令行执行“./server”启动服务程序,执行“netstat -na”查看有无server的服务端口。如果存在,则执行下面编写的客户程序“./client”。不过这仅是手工启动的方法,下面给出用服务管理程序管理server程序的方法。只要在目录/etc/rc.d/init.d下放入服务程序的脚本就能被服务程序读到。在命令行执行“touch server”创建文件server,并将文件属性改成可执行。在管理程序中并不能看到此服务名,脚本文件必须有一些结构才能被管理程序认为是服务程序脚本。

为了减少工作量,拷贝/etc/rc.d/init.d下脚本httpd,将拷贝脚本名命名为server,然后对其编辑。

(1)执行“cp httpd server”。

(2)用文本编辑器vi(其它编辑器亦可)将server打开进入编辑状态。首先用字符串server替换httpd。然后找到daemon server行,如果编写的程序放在变量PATH目录中,不需要修改此行;如果把服务程序放在其它目录中,就要写服务的全路径。例如程序在/root的目录中,就要写成daemon /root/server,还要删除“rm -f /var/run/server.pid”这一行。

(3)执行“chmod 755 server”,将server属性设定为可执行。

此时就可以用chkconfig、ntsysv等工具,在希望的运行级中增加这个新服务程序,然后测试客户机与服务器能否通信。

被xinetd调用的服务程序

在Linux系统中,有很多服务是被xinetd(较早版本使用的是inetd)超级守护服务器启动的。其实凡是基于TCP和UDP的服务都可使用超级守护进程启动,只是在服务量很大影响效率的情况下不被采用。

1.依赖xinetd启动的服务建立通信过程

为了与独立服务器程序比较,我们看一下依赖xinetd的服务器是如何启动的。

(1)xinetd启动时读取/etc/xinetd目录中的文件(早期版本为/etc/inetd文件),根据其中的内容给所有允许启动的服务创建一个指定类型的套接口,并将套接口放入select()中的描述符中。

(2)对每个套接口绑定bind(),所用的端口号和其它参数来自/etc/xinetd目录下每个服务的配置文件。

(3)如果是TCP套接口就调用函数listen(),等待用户连接。如果是UDP套接口,就不需调用此函数。

(4)所有套接口建立后,调用函数select()检查哪些套接口是活动的。

(5)若select()返回TCP套接口,就调用accept()接收这个连接。如果为UDP,就不需调用此函数。

(6)xinetd调用fork()创建子进程,由子进程处理连接请求。

◆ 子进程关闭所有其它描述符,只剩下套接口描述符。这个套接口描述符对于TCP是accept()返回的套接口,对于UDP为最初建立的套接口。然后子进程连续三次dup()函数,将套接口描述符复制到0、1和2,它们分别对应标准输入、标准输出和标准错误输出,并关闭套接口描述符。

◆ 子进程查看/etc/xinetd下文件中的用户,如果不是root用户,就用调用命令setuid和setgid将用户ID和组ID改成文件中指定的用户。

(7)对于TCP套接口,与用户交流结束后父进程需要关闭已连接套接口。父进程重新处于select()状态,等待下一个可读的套接口。

最后调用配置文件中指定的外部服务程序,外部程序启动后就可与用户进行信息传递了。

2.为xinetd编写专门的服务程序

除了独立服务程序能被xinetd启动外,还可以为xinetd编写专门的程序。此处的例子程序与上面server.c功能相同。不过两者的程序区别是很大的,此例的代码仅相当于上面传输数据的部分。我们还将程序名定为server.c,所以不能放在相同目录中,同名仅是为了和上面程序对照。

#include “unistd.h”

int main()

{

char ch;

read(0,&ch,1);

ch++;

write(1,&ch,1);

}

将程序编译成可执行文件,并做些设置就可被xinetd启动。注意不要和上面的独立服务程序server一起启动,因为客户程序写得比较简单,访问的是固定端口,服务器都设成了相同的端口号。

(1)编辑/etc/services文件,在行末增加一条记录:

server 9000/tcp

(2)在目录/etc/xinetd.d下编写文件server,内容为:

service server

{

disable = no

socket_type = stream

protocol = tcp

wait = no

user = root

server = /home/test/server (此处设置成自己程序所在的目录)

}

如果使用的是较早版本,则需在/etc/inetd.conf文件中添加下面的行:

server tcp nowait root /path/to/yourdirectory/server

(3)执行/etc/rc.d/initd.d/xinetd restart重新启动xinetd服务器。早期版本执行/etc/rc.d/initd.d/inetd restart重新启动inetd。

(4)执行netstat -an查看有没有server程序使用的端口号,如果有就可使用下面客户机程序进行测试了。

客户机程序

下面就客户机函数做一简单介绍。

//程序名client.c

/*功能:从客户的控制台输入一个字符,然后将这个字符送到服务器,并将服务器返回的字符显示出来*/

#include “sys/types.h”

#include “sys/socket.h”

#include “stdio.h”

#include “netinet/in.h”

#include “arpa/inet.h”

#include “unistd.h”

int main()

{

int sockfd;//

int address_len;

int connect_flag;

struct sockaddr_in address;

int connect_result;

char client_ch,server_ch;

函数socket()用于建立一个套接口,创建成功返回套接口描述符。

sockfd=socket(AF_INET,SOCK_STREAM,0);

if(sockfd

{

printf(“sockfd error /n”);

}

address.sin_family=AF_INET;

address.sin_addr.s_addr=inet_addr(“192.168.0.1”);/*读者根据自己环境改成服务器地址*/

address.sin_port=htons(9000);

address_len=sizeof(address);

函数connect()用于与服务器建立一个主动连接,调用成功返回值为0。

connect_flag=connect(sockfd,(struct sockaddr *)&address,address_len);

if(connect_flag==-1)

{

perror(“client”);

exit(1);

}

printf(“Input a character :”);

函数scanf()用于从控制台输入一个字符,并将字符存入client_ch的地址。函数write()和read()用于传输数据。函数printf()在客户机屏幕上显示服务器传回的字符。函数close()关闭套接口。

scanf(“%c”,&client_ch);

write(sockfd,&client_ch,1);

read(sockfd,&server_ch,1);

printf(“character from server : %c/n”,server_ch);

close(sockfd);

exit(0);

}

执行命令“gcc -o client client.c”,将client.c编译成client。执行“./client”,在程序提示下输入一个字符,就能看到服务器传回的字符。

以上介绍的仅是简单的例子。平时见到的服务程序远比它复杂,而且很多是多协议服务程序或是多协议多服务程序。多协议服务程序就是在main()中分别创建供服务的TCP和UDP套接口。为每个服务分别写出相应程序好处是便于控制,但是这样每个服务都启动两个服务器,而它们的算法响应是一样的,就要耗费不必要的资源,并且出了问题排错也较困难。多服务是将不同的服务集成在一起由一个程序完成,可用一个数组表示服务,数组中的每一项表示某协议某服务的一种,这样很容易扩展程序的服务功能。

用B/S或者C/S等,以及WebSerice等模式。 服务还是在Windows上,而使用者在Linux上。没有必要非要把服务和使用者放在同一个平台。具体介绍参考《Linux就该这么学》。

怎样查询linux系统调用函数

你用系统调用号来调用函芹档数,不如直接用函数名字调用,汇编中也支持用函数名字调用啊,先压入参数,再call就可以了。例嫌闹乱弯旁如push

;call

open

以下是Linux系统调用的一个列表,包含了大部分常用系统调用和由系统调用派生出的的函数。这可能是你在互联网上所能看到的唯一一篇中文注释的Linux系统调用列表,即使是简单的字母序英文列表,能做到这么完全也是很罕见的。

  按照惯例,这个列表以man pages第2节,即系统调用节为蓝本。按照笔者的理解,对其作了大致的分类,同毁迅瞎时也作了一些小小的修改,删去了几个仅供内核使用,不允许用户调用的系统调用,对个别本人稍觉不妥的地方作了一些小的修改,并对所有列出的系统调用附上简要注释。  

  其中有一些函数的作用完全相同,只是参数不同。(可能很多熟悉C++朋友马上就能联想起函数重载,但是别忘了Linux核心是用C语言写的,所以只能取成不同的函数名)。还有一些函数已经过时,被新的更好的函数所代替了(gcc在链接这些函数时会发出警告),但因为兼容的原因还保留着,这些函数我会在前面标上“*”号以示区别。

一、进程控制:

fork 创建一个新进程

clone 按指定条件创建子进程

execve 运行可执行文件

exit 中止进程

_exit 立即中止当前进程

getdtablesize 进程所能打开的更大文件数

getpgid 获取指定进程组标识号

setpgid 设置指定进程组标志号

getpgrp 获取当前进程组标识号

setpgrp 设置当前进程组标志号

getpid 获取进程标识号

getppid 获取父进程标识号

getpriority 获取调度优先级

setpriority 设置调度优先级

modify_ldt 读写进程的本地描述表

nanosleep 使进程睡眠指定的时间

nice 改变分时进程的优先级

pause 挂起进程,等纤空待信号

personality 设置进程运行域

prctl 对进程进行特定操作

ptrace 进程跟踪

sched_get_priority_max 取得静态优先级的上限

sched_get_priority_min 取得静态优先级的下限

sched_getparam 取得进程的调度参数

sched_getscheduler 取得指定进程的调度策略

sched_rr_get_interval 取得按RR算法调度的实时进程的时间片长度

sched_setparam 设置进程的调度参数

sched_setscheduler 设置指定进程的调度策略和参数

sched_yield 进程主动让出处理器,并将自己等候调度队列队尾

vfork 创建一个子进程,以供执行新程序,常与execve等同时使用

wait 等待子进程终止

wait3 参见wait

waitpid 等待指定子进程终止

wait4 参见waitpid

capget 获取进程权限

capset 设置进程权限

getsid 获取会晤标识号

setsid 设置会晤标识号

二、文件系统控制

1、文件读写操作

fcntl 文件控制

open 打开文件

creat 创建新文件

close 关闭文件描述字

read 读文件

write 写文件

readv 从文件读入数据昌信到缓冲数组中

writev 将缓冲数组里的数据写入文件

pread 对文件随机读

pwrite 对文件随机写

lseek 移动文件指针

_llseek 在64位地址空间里移动文件指针

dup 复制已打开的文件描述字

dup2 按指定条件复制文件描述字

flock 文件加/解锁

poll I/O多路转换

truncate 截断文件

ftruncate 参见truncate

umask 设置文件权限掩码

fsync 把文件在内存中的部分写回磁盘

2、文件系统操作

access 确定文件的可存取性

chdir 改变当前工作目录

fchdir 参见chdir

chmod 改变文件方式

fchmod 参见chmod

chown 改变文件的属主或用户组

fchown 参见chown

lchown 参见chown

chroot 改变根目录

stat 取文件状态信息

lstat 参见stat

fstat 参见stat

statfs 取文件系统信息

fstatfs 参见statfs

readdir 读取目录项

getdents 读取目录项

mkdir 创建目录

mknod 创建索引节点

rmdir 删除目录

rename 文件改名

link 创建链接

symlink 创建符号链接

unlink 删除链接

readlink 读符号链接的值

mount 安装文件系统

umount 卸下文件系统

ustat 取文件系统信息

utime 改变文件的访问修改时间

utimes 参见utime

quotactl 控制磁盘配额

三、系统控制

ioctl I/O总控制函数

_sysctl 读/写系统参数

acct 启用或禁止进程记账

getrlimit 获取系统资源上限

setrlimit 设置系统资源上限

getrusage 获取系统资源使用情况

uselib 选择要使用的二进制函数库

ioperm 设置端口I/O权限

iopl 改变进程I/O权限级别

outb 低级端口操作

reboot 重新启动

swapon 打开交换文件和设备

swapoff 关闭交换文件和设备

bdflush 控制bdflush守护进程

sysfs 取核心支持的文件系统类型

sysinfo 取得系统信息

adjtimex 调整系统时钟

alarm 设置进程的闹钟

getitimer 获取计时器值

setitimer 设置计时器值

gettimeofday 取时间和时区

settimeofday 设置时间和时区

stime 设置系统日期和时间

time 取得系统时间

times 取进程运行时间

uname 获取当前UNIX系统的名称、版本和主机等信息

vhangup 挂起当前终端

nfsservctl 对NFS守护进程进行控制

vm86 进入模拟8086模式

create_module 创建可装载的模块项

delete_module 删除可装载的模块项

init_module 初始化模块

query_module 查询模块信息

*get_kernel_syms 取得核心符号,已被query_module代替

四、内存管理

brk 改变数据段空间的分配

rk 参见brk

mlock 内存页面加锁

munlock 内存页面解锁

mlockall 调用进程所有内存页面加锁

munlockall 调用进程所有内存页面解锁

mmap 映射虚拟内存页

munmap 去除内存页映射

mremap 重新映射虚拟内存地址

msync 将映射内存中的数据写回磁盘

mprotect 设置内存映像保护

getpagesize 获取页面大小

sync 将内存缓冲区数据写回硬盘

cacheflush 将指定缓冲区中的内容写回磁盘

五、网络管理

getdomainname 取域名

setdomainname 设置域名

gethostid 获取主机标识号

sethostid 设置主机标识号

gethostname 获取本主机名称

sethostname 设置主机名称

六、socket控制

socketcall socket系统调用

socket 建立socket

bind 绑定socket到端口

connect 连接远程主机

accept 响应socket连接请求

send 通过socket发送信息

sendto 发送UDP信息

sendmsg 参见send

recv 通过socket接收信息

recvfrom 接收UDP信息

recvmsg 参见recv

listen 监听socket端口

select 对多路同步I/O进行轮询

shutdown 关闭socket上的连接

getsockname 取得本地socket名字

getpeername 获取通信对方的socket名字

getsockopt 取端口设置

setsockopt 设置端口参数

sendfile 在文件或端口间传输数据

socketpair 创建一对已联接的无名socket

七、用户管理

getuid 获取用户标识号

setuid 设置用户标志号

getgid 获取组标识号

setgid 设置组标志号

getegid 获取有效组标识号

setegid 设置有效组标识号

geteuid 获取有效用户标识号

seteuid 设置有效用户标识号

setregid 分别设置真实和有效的的组标识号

setreuid 分别设置真实和有效的用户标识号

getresgid 分别获取真实的,有效的和保存过的组标识号

setresgid 分别设置真实的,有效的和保存过的组标识号

getresuid 分别获取真实的,有效的和保存过的用户标识号

setresuid 分别设置真实的,有效的和保存过的用户标识号

setfsgid 设置文件系统检查时使用的组标识号

setfsuid 设置文件系统检查时使用的用户标识号

getgroups 获取后补组标志清单

setgroups 设置后补组标志清单

八、进程间通信

ipc 进程间通信总控制调用

1、信号

sigaction 设置对指定信号的处理方法

sigprocmask 根据参数对信号集中的信号执行阻塞/解除阻塞等操作

sigpending 为指定的被阻塞信号设置队列

sigsuspend 挂起进程等待特定信号

signal 参见signal

kill 向进程或进程组发信号

*sigblock 向被阻塞信号掩码中添加信号,已被sigprocmask代替

*siggetmask 取得现有阻塞信号掩码,已被sigprocmask代替

*sigsetmask 用给定信号掩码替换现有阻塞信号掩码,已被sigprocmask代替

*sigmask 将给定的信号转化为掩码,已被sigprocmask代替

*sigpause 作用同sigsuspend,已被sigsuspend代替

sigvec 为兼容BSD而设的信号处理函数,作用类似sigaction

ssetmask ANSI C的信号处理函数,作用类似sigaction

2、消息

msgctl 消息控制操作

msgget 获取消息队列

msgsnd 发消息

msgrcv 取消息

3、管道

pipe 创建管道

4、信号量

semctl 信号量控制

semget 获取一组信号量

semop 信号量操作

5、共享内存

shmctl 控制共享内存

shmget 获取共享内存

shmat 连接共享内存

shmdt 拆卸共享内存

关于linux c listen函数的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。


数据运维技术 » Linux C中的listen函数及其应用 (linux c listen函数)