select端口复用技术
时间: 2024-01-19 07:01:04 浏览: 35
端口复用技术是一种在网络编程中常用的技术,可以让多个应用程序共享同一个端口进行通信。常见的端口复用技术有SO_REUSEADDR和SO_REUSEPORT两种。
其中,SO_REUSEADDR选项可以让一个处于TIME_WAIT状态的端口立即被重用,而SO_REUSEPORT选项则可以让多个应用程序绑定到同一个IP地址和端口上。这两种技术都可以提高网络应用程序的性能和可扩展性。
相关问题
使用select端口复用技术,实现一个聊天程序的服务器端的代码
好的,以下是使用select端口复用技术实现聊天程序服务器端的代码示例,仅供参考:
```python
import select
import socket
HOST = '127.0.0.1' # 服务器IP地址
PORT = 6666 # 服务器端口号
BACKLOG = 5 # 最大连接数
RECV_BUFFER = 1024 # 接收数据缓存大小
# 创建socket对象并绑定IP地址和端口号
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(BACKLOG)
input_list = [server_socket] # select函数监听的输入列表
client_dict = {} # 客户端socket字典
def broadcast_msg(sock, message):
# 广播消息给所有在线客户端
for client_sock in client_dict.values():
if client_sock != sock:
client_sock.send(message.encode('utf-8'))
while True:
# 使用select函数监听输入列表
read_sockets, write_sockets, error_sockets = select.select(input_list, [], [])
for sock in read_sockets:
if sock == server_socket:
# 新客户端连接
client_socket, client_address = server_socket.accept()
input_list.append(client_socket)
client_dict[client_socket] = client_address
print('Client %s:%s connected.' % client_address)
broadcast_msg(client_socket, 'Client %s:%s entered room.\n' % client_address)
else:
# 客户端发送消息
try:
data = sock.recv(RECV_BUFFER).decode('utf-8')
if data:
print('[%s:%s] %s' % (client_dict[sock][0], client_dict[sock][1], data))
broadcast_msg(sock, '[%s:%s] %s' % (client_dict[sock][0], client_dict[sock][1], data))
except:
# 客户端意外退出
print('Client %s:%s disconnected.' % client_dict[sock])
broadcast_msg(sock, 'Client %s:%s left room.\n' % client_dict[sock])
sock.close()
input_list.remove(sock)
del client_dict[sock]
continue
server_socket.close()
```
以上是一个简单的Python聊天程序服务器端的实现,使用了select端口复用技术来监听多个客户端连接和消息发送。当有新客户端连接时,服务器广播一条消息给所有在线客户端;当客户端发送消息时,服务器打印消息并广播给其他在线客户端;当客户端意外退出时,服务器广播一条消息并删除该客户端的socket连接。
使用select端口复用技术,实现一个聊天程序的服务器端的C++代码
一、select 端口复用技术介绍
select 函数可以实现多路复用输入/输出,即一个进程可以同时监听多个文件句柄,以便在任意一个文件句柄上完成输入输出操作。
select 函数使用一个 fd_set 类型的数组来检测一组文件描述符的状态。fd_set 变量的具体定义如下:
```
typedef struct fd_set {
u_int fds_bits[howmany(FD_SETSIZE, NFDBITS)];
} fd_set;
```
其中 howmany 和 NFDBITS 定义在头文件 sys/param.h 中,其功能主要是做一些与文件描述符相关的计算。
select 函数的原型如下:
```
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
```
参数 nfds: 所有描述符的最大值加 1.
参数 readfds, writefds, exceptfds 分别指向可读、可写和异常事件的 fd_set 集合。
参数 timeout 为等待该文件描述符集合变化的最大超时时间。如果为 NULL,则函数会一直阻塞直到有描述符集合中的事件发生。
成功时,该函数会返回待处理事件的文件数量。如果在超时时间内没有检测到任何文件,则返回 0,如果函数发生错误,返回 -1。
二、聊天程序服务器端C代码实现
下面是一个基于 select 的服务器端聊天程序的 C 代码实现,其中包含了接收和转发客户端发送消息的功能:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#define MAX_CLIENTS 5
#define BUFFER_SIZE 1024
int server_socket;
void die(char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}
int init_server(char *ip, int port) {
int sockfd;
struct sockaddr_in servaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
die("socket");
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
if (ip == NULL) {
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
} else {
if (inet_pton(AF_INET, ip, &servaddr.sin_addr) <= 0) {
die("inet_pton");
}
}
if (bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
die("bind");
}
if (listen(sockfd, MAX_CLIENTS) < 0) {
die("listen");
}
return sockfd;
}
int main(int argc, char **argv) {
struct sockaddr_in client_addr;
int maxfd = -1, max_i = -1;
char buffer[BUFFER_SIZE];
fd_set rset, all_set;
int clients[MAX_CLIENTS];
int i, maxi = -1;
for (i = 0; i < MAX_CLIENTS; i++) {
clients[i] = -1;
}
server_socket = init_server(NULL, 12345);
FD_ZERO(&all_set);
FD_SET(server_socket, &all_set);
maxfd = server_socket;
while (1) {
rset = all_set;
int nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (nready < 0) {
die("select");
}
if (FD_ISSET(server_socket, &rset)) {
socklen_t len = sizeof(client_addr);
int connfd;
if ((connfd = accept(server_socket, (struct sockaddr*) &client_addr, &len)) < 0) {
die("accept");
}
for (i = 0; i < MAX_CLIENTS; i++) {
if (clients[i] < 0) {
clients[i] = connfd;
break;
}
}
if (i == MAX_CLIENTS) {
fprintf(stderr, "too many clients\n");
close(connfd);
continue;
}
printf("New client connected from %s:%d\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
FD_SET(connfd, &all_set);
if (connfd > maxfd) {
maxfd = connfd;
}
if (i > maxi) {
maxi = i;
}
if (--nready <=0) {
continue;
}
}
for (i = 0; i <= maxi; i++) {
int sockfd = clients[i];
if (sockfd < 0) {
continue;
}
if (FD_ISSET(sockfd, &rset)) {
ssize_t n = recv(sockfd, buffer, BUFFER_SIZE-1, 0);
if (n < 0) {
die("recv");
}
if (n == 0) {
FD_CLR(sockfd, &all_set);
close(sockfd);
clients[i] = -1;
} else {
buffer[n] = '\0';
printf("Received message: %s", buffer);
for (int j = 0; j <= maxi; j++) {
int dest_sockfd = clients[j];
if (dest_sockfd < 0 || dest_sockfd == sockfd) {
continue;
}
if (send(dest_sockfd, buffer, strlen(buffer), 0) < 0) {
die("send");
}
}
}
if (--nready <= 0) {
break;
}
}
}
}
return EXIT_SUCCESS;
}
```
该程序使用了 MAX_CLIENTS 个 TCP 连接,对于每个连接在缓冲区的最大长度为 BUFFER_SIZE。程序使用了一个循环来监听所有连接,如果有连接上来,程序将把它加入到待监听文件句柄集合中。程序每次循环都需要调用 select 函数来检测每个连接上事件的发生情况,接着程序根据事件类型来进行相应的处理。如果是有连接到来,程序就将该连接加入到待监听的文件句柄集合中,并记录该连接的描述符,在最大描述符的范围内更新相应的值;如果是有客户端发来消息,程序就遍历所有连接并将消息转发到其他客户端上。
相关推荐
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)