我是靠谱客的博主 炙热戒指,最近开发中收集的这篇文章主要介绍select多连接处理1、select接口函数:2、和select一起使用的宏3、server端代码 4、client端代码,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在物联网socket通信时,对于多客户访问,或多个连接通信,一般不采用多线程处理,而是使用select。selcet可以在一个线程内同时处理多个socket的IO请求。

1、select接口函数:

int select(int maxfdp, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeval *timeout);

 参数说明:

maxfdp:被监听的文件描述符的总数,它比所有文件描述符集合中的文件描述符的最大值大1,因为文件描述符是从0开始计数的;

readfds、writefds、exceptset:分别指向可读、可写和异常等事件对应的描述符集合。

timeout:用于设置select函数的超时时间,为NULL 表示无限等待,timeval结构体定义如下:

struct timeval
{      
    long tv_sec;   /*秒 */
    long tv_usec;  /*微秒 */   
};
返回值:超时返回0;失败返回-1;成功返回大于0的整数,表示就绪描述符的数目。

2、和select一起使用的宏

FD_ZERO(fd_set *fdset):清空fdset与所有文件句柄的联系。

FD_SET(int fd, fd_set *fdset):建立文件句柄fd与fdset的联系。

FD_CLR(int fd, fd_set *fdset):清除文件句柄fd与fdset的联系。

FD_ISSET(int fd, fd_set *fdset):检查fdset联系的文件句柄fd是否可读写,当>0表示可读写。

3、server端代码

/*
主要功能:
1、建立socket,监听连接;
2、支持多个客户端连接;
3、客户端断开时释放资源;
4、接收数据并打印字符串,回复ok。
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define TCP_PORT
12321
#define CLIENT_MAX_NUMB
8
#define BUFFER_MAX_LEN
1500
//接收数据处理
int recv_data_handle(char *data, int len)
{
int i;
if(len <= 0){
return -1;
}
printf("recv len: %d, data:n", len);
for(i = 0; i < len; i++){
if(i !=0 && i%16 == 0){
printf("n");
}
printf("%02X ", data[i]);
}
printf("n");
return 0;
}
//TCP server
int main(void)
{
int i = 0;
int j = 0;
int ret = 0;
int tcp_fd = -1;
int new_fd = -1;
int max_fd = 0;
fd_set readfds;
int len;
char buf[BUFFER_MAX_LEN];
struct timeval time_out;
int on = 1;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t sin_size;
int client_fd[CLIENT_MAX_NUMB];
//创建TCP
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(TCP_PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//创建socket
tcp_fd = socket(AF_INET, SOCK_STREAM, 0);
//允许端口复用
if(setsockopt(tcp_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0){
printf("setsockopt error!n");
goto RET;
}
//绑定
if(bind(tcp_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){
printf("bind error!n");
goto RET;
}
//监听
if(listen(tcp_fd, 0) < 0){
printf("listen error!n");
goto RET;
}
printf("tcp create okn");
for(i = 0; i < CLIENT_MAX_NUMB; i++){
client_fd[i] = -1;
}
while(1){
FD_ZERO(&readfds);
if(tcp_fd >= 0){
FD_SET(tcp_fd, &readfds);
}
for(i = 0; i < CLIENT_MAX_NUMB; i++){
if(client_fd[i] >= 0){
FD_SET(client_fd[i], &readfds);
}
}
max_fd = tcp_fd;
for(i = 0; i < CLIENT_MAX_NUMB; i++){
if(max_fd < client_fd[i]){
max_fd = client_fd[i];
}
}
time_out.tv_usec = 0;
time_out.tv_sec = 2;
ret = select(max_fd+1, &readfds, NULL, NULL, &time_out);
if (ret < 0){
break;
}
if (ret == 0){
printf("seclet time out...n");
continue;
}
for(i = 0; i < ret; i++){
if(FD_ISSET(tcp_fd, &readfds)){
//接收新连接
memset(&client_addr, 0, sizeof(client_addr));
sin_size = sizeof(client_addr);
new_fd = accept(tcp_fd, (struct sockaddr *)(&client_addr), &sin_size);
if(new_fd < 0){
printf("accept errorn");
continue;
}
printf("accept a client!naddr = %s:%dn", inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
for(j = 0; j < CLIENT_MAX_NUMB; j++){
if(client_fd[j] < 0){
client_fd[j] = new_fd;
break;
}
}
if(j == CLIENT_MAX_NUMB){
printf("client too machn");
close(new_fd);
}
continue;
}
//处理多个客户端数据
for(j = 0; j < CLIENT_MAX_NUMB; j++){
if(client_fd[j] < 0){
continue;
}
if(FD_ISSET(client_fd[j], &readfds)){
memset(buf, 0, BUFFER_MAX_LEN);
len = recv(client_fd[j], buf, BUFFER_MAX_LEN, 0);
if(len <= 0){
close(client_fd[j]);
client_fd[j] = -1;
printf("recv data errorn");
continue;
}
printf("nrecv, client[%d]: %sn", j, buf);
//recv_data_handle(buf, len);
send(client_fd[j], "ok", strlen("ok"), 0);
printf("send, client[%d]: oknn", j);
}
}
}
}
RET:
//关闭所有client fd
for(i = 0; i < CLIENT_MAX_NUMB; i++){
if(client_fd[i] > 0){
close(client_fd[i]);
client_fd[i] = -1;
}
}
//关闭server fd
close(tcp_fd);
tcp_fd = -1;
printf("select error, exit!n");
return -1;
}

 4、client端代码

/*
功能:
1、自动连接本地服务器端;
2、间隔发送数据hello,并打印回复;
3、服务器断开自动重连;
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <time.h>
#define SERVER_PORT 12321
#define BUFFER_MAX_LEN
1500
int main(void)
{
int ret;
int len;
int max_fd;
int client_fd = -1;
int numb = 2;
struct sockaddr_in addr;
char buf[BUFFER_MAX_LEN];
fd_set readfds;
struct timeval time_out;
// 套接字信息
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(SERVER_PORT);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
while(1)
{
if(client_fd < 0){
// 建立套接字
client_fd = socket( AF_INET, SOCK_STREAM, 0);
if(client_fd < 0){
printf("Socket Errorn");
return -1;
}
// 链接server
if(connect(client_fd, ( struct sockaddr * )&addr, sizeof(addr)) < 0){
printf("Connect errorn");
close(client_fd);
client_fd = -1;
sleep(2);
continue;
}
printf("conent ok!nn");
}
FD_ZERO(&readfds);
FD_SET(client_fd, &readfds);
max_fd = client_fd;
time_out.tv_usec = 0;
time_out.tv_sec = 2;
if(numb++ == 3 && client_fd >= 0){
numb = 0;
send(client_fd, "hello", strlen("hello"), 0);
printf("send: hellon");
};
ret = select(max_fd+1, &readfds, NULL, NULL, &time_out);
if(ret < 0){
printf("Client Select Error..n");
goto RET;
}
if(ret == 0){
continue;
}
if(FD_ISSET(client_fd, &readfds)){
memset(buf, 0, sizeof(buf));
len = recv(client_fd, buf, BUFFER_MAX_LEN, 0);
if(len > 0){
printf("recv: %snn", buf);
}
if(len == 0){
close(client_fd);
client_fd = -1;
}
}
}
RET:
close(client_fd);
printf("Exitn");
return 0;
}

最后

以上就是炙热戒指为你收集整理的select多连接处理1、select接口函数:2、和select一起使用的宏3、server端代码 4、client端代码的全部内容,希望文章能够帮你解决select多连接处理1、select接口函数:2、和select一起使用的宏3、server端代码 4、client端代码所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部