Linux C编程:端口监听实现方法 (linux c 端口监听)

在网络通信中,端口是用来区分不同应用程序的标识符。每个应用程序都需要侦听一个端口来接收来自网络的数据传输。对于Linux C 编程而言,实现端口监听是非常重要的一项功能。本文将介绍Linux C编程中常见的端口监听实现方法。

1. 使用socket系统调用

socket(套接字)是Linux系统中用于网络通信的重要API之一。通过socket,应用程序可以创建一个网络套接字,并通过这个套接字与网络进行通信。

在Linux C编程中,我们可以使用socket系统调用来创建一个监听套接字,从而实现端口的监听。下面是具体的步骤:

① 创建监听套接字

通过socket()函数创建一个监听套接字。这个函数的之一个参数指定协议族(比如,IPv4或IPv6),第二个参数指定套接字的类型(比如,TCP或UDP),第三个参数指定协议类型(通常为0,表示使用默认协议)。

int listening_socket = socket(AF_INET, SOCK_STREAM, 0);

② 绑定套接字到端口

使用bind()函数将监听套接字绑定到指定端口。这个函数的之一个参数是监听套接字,第二个参数是一个sockaddr结构体指针,用来描述端口和IP地址等信息。需要注意的是,sockaddr结构体的成员必须按照网络字节序进行填充。下面是一个示例:

struct sockaddr_in server_address;

memset(&server_address, 0, sizeof(server_address)); // 清空结构体

server_address.sin_family = AF_INET;

server_address.sin_port = htons(port_number); // 将端口号转换成网络字节序

server_address.sin_addr.s_addr = htonl(INADDR_ANY); // 等价于0.0.0.0,表示绑定到所有网卡上

int ret = bind(listening_socket, (struct sockaddr*)&server_address, sizeof(server_address));

③ 开始监听

使用listen()函数将监听套接字设置成被动监听状态,等待客户端发起连接请求。这个函数的之一个参数是监听套接字,第二个参数是等待连接请求的队列长度(通常为5)。

int ret = listen(listening_socket, 5);

④ 处理客户端连接

使用accept()函数接收客户端连接请求,并返回一个新的套接字,用于与客户端进行通信。这个函数的之一个参数是监听套接字,第二个参数是一个指向sockaddr结构体的指针,用于存储客户端的IP地址和端口号。需要注意的是,accept()函数是一个阻塞函数,如果没有客户端连接请求,程序将一直阻塞在这里。

struct sockaddr_in client_address;

socklen_t client_address_len = sizeof(client_address);

int client_socket = accept(listening_socket, (struct sockaddr*)&client_address, &client_address_len);

2. 使用select系统调用

在多并发的网络通信中,使用socket系统调用会带来一个重要的问题:阻塞。如果只有一个客户端连接请求,我们的程序仍然会阻塞在accept()函数处,无法响应其他客户端的请求。为了解决这个问题,可以使用select系统调用。

select()函数可以监听多个文件描述符,当其中有文件描述符就绪(比如可以读写)时,它会返回,并且可以通过FD_ISSET()宏判断哪些文件描述符已经就绪。下面是使用select()函数实现端口监听的基本步骤:

① 创建监听套接字

同样地,通过socket()函数创建一个监听套接字。

② 绑定套接字到端口

同样地,使用bind()函数将监听套接字绑定到指定端口。

③ 开始监听

同样地,使用listen()函数将监听套接字设置成被动监听状态,等待客户端发起连接请求。但是这里我们不会阻塞在accept()函数处。

int max_fd = listening_socket;

fd_set read_set;

fd_set ready_set;

FD_ZERO(&read_set);

FD_SET(listening_socket, &read_set);

while (1) {

ready_set = read_set;

int ret = select(max_fd+1, &ready_set, NULL, NULL, NULL);

if (ret

perror(“select”);

exit(-1);

}

if (FD_ISSET(listening_socket, &ready_set)) {

// 有连接请求,处理连接

} else {

// 有其他数据到达,处理数据

}

}

在循环中,我们先使用FD_ZERO()和FD_SET()宏将监听套接字添加到read_set中,然后不断监听中的文件描述符是否就绪。如果有文件描述符就绪,则使用FD_ISSET()宏判断具体是哪一个文件描述符就绪,然后进行相应的处理。需要注意的是,我们需要保证每次循环都重新赋值ready_set,因为这个会被select()函数修改。

3. 使用epoll系统调用

select系统调用虽然可以避免单线程、单进程网络编程中的阻塞问题,但是在高并况下性能和扩展性较差。为了解决这个问题,Linux内核引入了epoll系统调用。

epoll()函数可以同时监听多个文件描述符,并且只会将就绪的文件描述符加入到epoll实例中。这样,我们可以轻松地实现高并发网络编程。下面是使用epoll()函数实现端口监听的基本步骤:

① 创建epoll实例

使用epoll_create()函数创建一个epoll实例,返回一个文件描述符。这个函数的参数可以用来指定epoll实例中更大可以监听的文件描述符数量。

int epoll_fd = epoll_create(1024);

② 将监听套接字添加到epoll实例中

使用epoll_ctl()函数将监听套接字添加到epoll实例中,用于接收客户端连接请求。这个函数的之一个参数是epoll实例的文件描述符,第二个参数是指令类型(比如添加、删除、修改等),第三个参数是要监听的文件描述符,第四个参数是一个epoll_event结构体,用于指定事件类型和处理方式。

struct epoll_event event;

memset(&event, 0, sizeof(event));

event.events = EPOLLIN | EPOLLET; // 监听可读事件,边缘触发模式

event.data.fd = listening_socket; // 监听套接字的文件描述符

int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listening_socket, &event);

③ 循环监听套接字文件描述符

使用epoll_wt()函数循环监听epoll实例中的文件描述符,将就绪的文件描述符交给工作线程进行处理。这个函数的参数可以用来指定最多等待多长时间、最多等待多少文件描述符等。

struct epoll_event events[1024];

while (1) {

int n_ready = epoll_wt(epoll_fd, events, 1024, -1);

if (n_ready

perror(“epoll_wt”);

exit(-1);

}

for (int i = 0; i

int fd = events[i].data.fd;

if (fd == listening_socket) {

// 监听套接字就绪,处理连接请求

} else {

// 其他文件描述符就绪,处理数据

}

}

}

需要注意的是,epoll实例提供了两种触发模式:边缘触发模式和水平触发模式。边缘触发模式在文件描述符从未就绪变为就绪的瞬间触发,处理方式更为灵活。而水平触发模式则在文件描述符已经就绪的情况下持续触发,适用于稳定传输数据的场景。

端口监听是Linux C编程中非常重要的一项功能。本文介绍了三种常见的端口监听实现方法,分别是使用socket系统调用、select系统调用和epoll系统调用。读者可以根据自己的需求选择合适的方法进行开发。需要注意的是,网络编程中容易出现阻塞和死锁等问题,需要谨慎调试和处理,保证应用程序的稳定性和可靠性。

相关问题拓展阅读:

用C语言在Linux平台上写一个占用tcp8080端口的代码。

那你要做好久

#include

#include

#include

#include

#include

#include

#include

#include

int main()

{

int sockfd,new_fd;

struct sockaddr_in my_addr;

struct sockaddr_in their_addr;

int sin_size;

/埋衡/建立TCP套接口

if((sockfd = socket(AF_INET,SOCK_STREAM,0))==-1)

{

printf(“create socket error”);

perror(“socket”);

exit(1);

}

//初始化结构体,并绑定8080端口

my_addr.sin_family = AF_INET;

my_addr.sin_port = htons(8080);

my_addr.sin_addr.s_addr = INADDR_ANY;

bzero(&(my_addr.sin_zero),8);

//绑定套接口

if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))==-1)

{

perror(“bind socket error”);

exit(1);

}

//创建监听套接口

if(listen(sockfd,10)==-1)

{

perror(“listen”);

exit(1);

}

//等待连接

while(1)

{

sin_size = sizeof(struct sockaddr_in);

printf(“server is run.\n”);

//如果建立连接,将产生一个全新的套接字

if((new_fd = accept(sockfd,(struct sockaddr *)&their_addr,&sin_size))==-1)

{

perror(“accept”);

exit(1);

}

printf(“accept success.\n”);

//生成一个子进程来完成和客户端的会话,父进程继续监听

if(!fork())

{

printf(“create new thred success.\n”);

//读取客户端发来的信息

int numbytes;

char buff;

memset(buff,0,256);

if((numbytes = recv(new_fd,buff,sizeof(buff),0))==-1)

{

perror(“recv”);

exit(1);

}

printf(“%s”,buff);

//将从客户端接收到的信息再发回客户端

if(send(new_fd,buff,strlen(buff),0)==-1)

perror(“send”);

close(new_fd);

exit(0);

}

close(new_fd);

}

close(sockfd);

linux虚拟机怎么查看tcp协议端口

在Linux虚拟机中查看tcp协议端口,可以使用netstat命令,它可以显示当前系统中所有正在使用的网络端口以及网络连接状态。

1、查看所有TCP连接:

$ netstat -na | grep “tcp”

2、查看所有TCP监听端口:

$ netstat -na | grep “tcp” | grep “LISTEN”

3、查看指定端口的TCP连接:

$ netstat -na | grep “tcp” | grep “:80”

4、查看所有UDP端口

$ netstat -na | grep “udp”

5、查看指定端口的UDP连接

$ netstat -na | grep “udp” | grep “:53”

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


数据运维技术 » Linux C编程:端口监听实现方法 (linux c 端口监听)