红联Linux门户
Linux帮助

使用select函数接收客户端连接

发布时间:2011-11-25 21:05:10来源:红联作者:choice2009
服务端:
#include
#include
#include
#include
#include
#include
#include
#include
#include "wrap.h"
#define MAXLINE 80
#define SERVER_PORT 8000
//定义一个线程函数,用于处理select获取的socket连接。
void * get_connection(void *connection);
int main(void)
{
pid_t pid;
pthread_t tid;
sigset_t sigset;
struct sigaction newact, oldact;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len;
int listenfd, connectfd;
int i, n, maxi, maxfd, nready, client[FD_SETSIZE];
fd_set rset, allset;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];

//设置socket
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
//清空地址结构
bzero(&server_addr, sizeof(server_addr));
//初始化地址结构
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT);
//将地址与socket绑定
Bind(listenfd,(struct sockaddr *)&server_addr, sizeof(server_addr));

//设置最大监听数量
Listen(listenfd, 20);

printf("Accepting connections ...\n");

maxfd = listenfd;
maxi = -1;
for(i = 0; i< FD_SETSIZE; i++)
{
client[i] = -1;
}
//将allset清零,表示allset里没有任何可用的连接
FD_ZERO(&allset);

//将listened设置到allset,表示要监听该连接,当listenfd上有连接请求时将allset里的相应位置一
FD_SET(listenfd, &allset);

//开始循环,不停的去监视是否有连接。
while(1)
{
//将allset赋值给rset,allset用于每次循环时初始化rset
//FD_ZERO(&rset)
//FD_SET(listenfd,&rset)
//使用上面代码效果一样
rset = allset;
//使用slect进行异步监听连接,当有连接请求时在rset上相应位置一,select的返回值为select接受的连接的个数
nready = select(maxfd+1, &rset, NULL, NULL, NULL);
if(nready < 0)
perr_exit("select error");
//如果listenfd在rset上的相应位置一说明有客户端发起请求。
if(FD_ISSET(listenfd, &rset))
{
client_addr_len = sizeof(client_addr);
//接受一个新的连接
connectfd = Accept(listenfd, (struct sockaddr *)&client_addr, &client_addr_len);
perror("list");
//将可用的连接存入client数组。
for(i = 0; i< FD_SETSIZE; i++)
{
if(client[i] < 0)
{
client[i] = connectfd;
break;
}
}
//如果i等于FD_SETSIZE,说明已经到达可以存放的连接的最大值。
if(i == FD_SETSIZE)
{
fputs("too many clients\n",stderr);
exit(1);
}
//将connectfd加入到监听序列。
FD_SET(connectfd, &allset);
//如果connectfd大于需要监听的最大值,则将connectfd设置为监听的最大值。
if(connectfd > maxfd)
maxfd= connectfd;
//设置client数组中已经存储连接的最大数组下标。
if(i > maxi)
maxi = i;
//如果--nready后为0,说明只有一个可用连接,可以返回继续监听。
if(--nready == 0)
continue;
}

//循环处理可用的连接
for(i = 0; i <= maxi; i++)
{
//如果client[i]是-1,说明该值下没有存储可用的连接。
if((connectfd = client[i]) < 0)
continue;
//如果connectfd是可用的连接,则创建一个线程来处理该请求。
if(FD_ISSET(connectfd, &rset))
{
pthread_create(&tid, NULL, get_connection, &connectfd);
//将该连接清除出集合。
FD_CLR(connectfd, &allset);
//将client数组中存储connectfd连接的相应位置为-1,以用来存储后来的连接。
client[i] = -1;
//如果没有剩余的连接返回。
if(--nready == 0)
break;
}
}
}
return 0;
}

void * get_connection(void *connection)
{
int connect, n;
char buf[MAXLINE];
connect = *((int*)connection);
printf("%d---*%d\n",connect,*((int*)connection));
while((n = read(connect, buf, MAXLINE)) != 0)
{
int j;
for( j = 0; j< n; j++)
buf[j] = toupper(buf[j]);
write(connect, buf, n);
}
close(connect);
return NULL;
}

客户端:
#include
#include
#include
#include
#include

#define MAXLINE 80
#define SERVER_PORT 8000

int main(int argc ,char * argv[])
{
struct sockaddr_in server_addr;
char buf[MAXLINE];
int sockfd, n;
char * str;
int i = 10;

if(argc != 2)
{
return 0;
}
str = argv[1];

sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
server_addr.sin_port = htons(SERVER_PORT);
connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
while(i != 0)
{
write(sockfd, str, strlen(str));
n = read(sockfd, buf, MAXLINE);
write(STDOUT_FILENO, buf, n);
printf("\n");
sleep(1);
i--;
}
close(sockfd);
exit(2);
}
文章评论

共有 4 条评论

  1. akumar 于 2014-07-26 10:43:31发表:

    3# fengfengdiandia select函数最后一个参数不久是设置超时么

  2. zhangcasa 于 2012-07-19 14:08:19发表:

    wrap.h是什么

  3. fengfengdiandia 于 2012-07-19 09:17:42发表:

    [code] nready = select(maxfd+1, &rset, NULL, NULL, NULL);
    if(nready < 0) // 万一超时怎么办,没做处理么
    perr_exit("select error");
    [/code]

  4. Agreed 于 2011-11-26 09:02:04发表:

    不懂