1. 描述
1.1 流程描述
a. 刚开始时select只轮询listenfd
b. 当有client连接时,把accept之后的client的sockfd,加入到select中
c. 这样select既轮询listenfd又轮询client的sockfd
d. 当client有连接时,重复b
e. 当client有数据时,读数据并返回
2. 源码
2.1 tcpserv.c
-
cong@msi:/work/test/tcpip/12select/serv$ cat tcpserv.c
-
#include "utils.h"
-
-
int main ( int argc, char *argv[] )
-
{
-
ssize_t n;
-
int i, maxi, maxfd;
-
int listenfd, connfd, sockfd;
-
int nready, client[FD_SETSIZE];
-
struct sockaddr_in servaddr, cliaddr;
-
fd_set rset, allset;
-
char buf[MAXLINE];
-
socklen_t clilen;
-
listenfd = socket(AF_INET, SOCK_STREAM, 0); --> 1. socket
-
if(listenfd< 0)
-
return -1;
-
bzero(&servaddr, sizeof(servaddr));
-
servaddr.sin_family = AF_INET;
-
servaddr.sin_port = htons(13999);
-
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
-
//inet_pton(AF_INET, TIME_SERV_ADDR, &servaddr.sin_addr);
-
-
bind(listenfd, (const struct sockaddr*)&servaddr, sizeof(servaddr)); --> 2. bind
-
listen(listenfd, LISTENQ); --> 3. listen
-
maxfd = listenfd;
-
maxi = -1;
-
for(i=0; i<FD_SETSIZE; i++)
-
client[i] = -1;
-
FD_ZERO(&allset);
-
FD_SET(listenfd, &allset);
-
while(1)
-
{
-
rset = allset;
-
nready = select(maxfd+1, &rset, NULL, NULL, NULL); //刚开始时只监测listenfd,当有client连入时
-
if(nready<0) //既监测listenfd又监测client
-
continue;
-
if(FD_ISSET(listenfd, &rset)) //new client connection
-
{
-
clilen = sizeof(cliaddr);
-
connfd = accept(listenfd, (struct sockaddr*)&cliaddr,&clilen);
-
for(i=0; i<FD_SETSIZE; i++)
-
{
-
if(client[i] < 0)
-
{
-
client[i]=connfd;
-
break;
-
}
-
}
-
if(i==FD_SETSIZE)
-
dbmsg("too many clients");
-
FD_SET(connfd, &allset);
-
if(connfd > maxfd)
-
maxfd = connfd;
-
if(i>maxi)
-
maxi = i; //maxi记录连接了的client个数
-
if(--nready <= 0) //nready-->select监测到有变化的描述符个数
-
continue;
-
}
-
for(i=0; i<=maxi; i++)
-
{
-
if( (sockfd = client[i]) < 0)
-
continue;
-
if(FD_ISSET(sockfd, &rset))
-
{
-
if( (n=read(sockfd, buf, MAXLINE)) == 0) //当收到的数据个数为0时,说明client己关闭连接
-
{
-
close(sockfd);
-
FD_CLR(sockfd, &allset); //select不再轮询这个socket
-
client[i] = -1; //把client列表中这项置-1
-
}else
-
write(sockfd, buf, n); //当收到的数据个数不为0时,就把数据写到client端
-
if(--nready <= 0) //nready-->select监测到有变化的描述符个数
-
break;
-
}
-
}
-
}
-
return EXIT_SUCCESS;
-
}
nready-->select临测到有变化的描述符个数,既包括listen的描述符,又包括accept之后client的socket描述符,
-->当listen的描述符有变化时: 加入到select轮询队列,--nready
-->当client的socket描述符有变化时: for循环处理每一个描述符,--nready,当为0时说明所有变化的socket都处理完成,则break
2.2 utils.h
-
cong@msi:/work/test/tcpip/12select/serv$ cat utils.h
-
#ifndef UTILS_H__
-
#define UTILS_H__
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <sys/types.h> /* See NOTES */
-
#include <sys/socket.h>
-
#include <netinet/in.h>
-
#include <arpa/inet.h>
-
#include <time.h>
-
#include <string.h>
-
#include <errno.h>
-
#include <signal.h>
-
-
#define MAXLINE 1024
-
-
#define LISTENQ 10
-
#define dbmsg(fmt, args ...) printf("%s:%s[%d]: "fmt"\n", __FILE__,__FUNCTION__, __LINE__,##args)
-
#define max(a,b) ((a) > (b) ? (a) : (b))
-
-
#endif
serv.rar (下载后改名为serv.tar.gz)
client.rar (下载后改名为client.tar.gz)
阅读(1074) | 评论(0) | 转发(0) |