select端口复用技术
时间: 2024-01-19 11:06:04 浏览: 12
Port Multiplexing Technology (端口复用技术) refers to the process of combining multiple communication signals onto a single physical interface, thereby improving the data transfer efficiency of the network. Port multiplexing technology can be achieved through various means such as time division multiplexing, frequency division multiplexing, and code division multiplexing. Selective port multiplexing is one of the commonly used techniques in computer networking, which allows multiple applications to share a single port at the same time. This technique can be useful in scenarios where the number of available ports is limited, or when multiple applications need to access a common network resource.
相关问题
使用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)