I/O服用典型使用在下列网络应用场合: 当客户处理多个描述符(通常是交叉式输入和网络套接字)时,必须使用I/O服用。 一个客户同时处理多个套接字是可能的,不过比较少见。 如果一个TCP服务器既要处监听套接字,又要处理已连接套接字,一般就要使用I/O服用。 如果一个服务器既要使用TCP,又要使用UCP。一般就要使用I/O服用。 如果一个服务器要处理多个服务或多个协议。
1.cli_select.c
客户端从终端读入字符串,再发给服务器;需处理两个句柄。
#include <stdio.h>
#include <string.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/in.h>
#define SERV_IP "127.0.0.1"
//#define SERV_IP "192.168.2.1"
#define SERV_PORT 8123
#define MAXLINE 254
#define max(a,b) (a)>=(b)?(a):(b)
int str_cli (FILE * fp, int sockfd)
{
int maxfdp1, stdineof;
fd_set rset;
char buf[MAXLINE];
int n;
stdineof = 0;
for(;;)
{
if (stdineof == 0)
FD_SET(fileno(fp), &rset);
FD_SET(sockfd, &rset);
maxfdp1 = max(fileno(fp), sockfd) +1;
//printf("maxfdp1 = %d\n", maxfdp1);
select(maxfdp1, &rset, NULL, NULL, NULL);
if (FD_ISSET(sockfd, &rset))
{
if ((n = read(sockfd, buf, MAXLINE)) == 0)
{
if (stdineof == 1)
return;
else
{
printf("strcli:server terminated prematurely\n");
}
}
write(fileno(stdout),buf,n);
}
if (FD_ISSET(fileno(fp), &rset))
{
if ((n = read(fileno(fp), buf, MAXLINE)) == 0)
{
stdineof = 1;
shutdown(sockfd, SHUT_WR); /*SEND FIN*/
FD_CLR(fileno(fp), &rset);
continue;
}
write(sockfd, buf, n);
}
}
return 0;
}
void cli_init( int *sockfd)
{
struct sockaddr_in servaddr;
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, SERV_IP, &servaddr.sin_addr);
connect(*sockfd, (struct sockaddr*) &servaddr, sizeof(servaddr));
printf("connect\n");
return;
}
int main(int argc, char *argv[])
{
int sockfd;
cli_init( &sockfd);
str_cli(stdin, sockfd);
return 0;
}
2.ser_select.c
服务器接收客户端发来的字符串,并回传给客户端。单进程监听多个服务器。
/* ************************************************************************
* Filename: ser_select.c
* Description:
* Version: 1.0
* Created: 08/07/18 02:00:22
* Revision: none
* Compiler: gcc
* Author: YOUR NAME (),
* Company:
* ************************************************************************/
#include <stdio.h>
#include <string.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/in.h>
#define SERV_PORT 8123
#define MAXLINE 254
#define LISTENQ 5
int main(int argc, char *argv[])
{
int i , maxi, maxfd, listenfd, connfd, sockfd;
int nready, client[FD_SETSIZE];
ssize_t n;
fd_set rset, allset;
char buf[MAXLINE];
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind(listenfd, (struct sockaddr*) &servaddr, sizeof(servaddr));
listen(listenfd, LISTENQ);
maxfd = listenfd;
maxi = -1;
for (i = 0; i < FD_SETSIZE; i ++)
{
client[i] = -1;
}
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
for (;;)
{
rset = allset;
nready = select(maxfd+1, &rset, NULL, NULL, NULL);
printf("select\n");
if (FD_ISSET(listenfd, &rset))
{
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);
printf("accept\n");
for (i = 0; i < FD_SETSIZE; i++)
{
if (client[i] < 0)
{
client[i] = connfd; /* save descriptor */
break;
}
}
if (i == FD_SETSIZE)
{
printf("too many clients\n");
}
FD_SET(connfd, &allset);
if (connfd > maxfd)
maxfd = connfd;/* select */
if (i > maxi)
{
maxi = i;
}
if (--nready <=0)
{
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 )
{
printf("read n = %d\n", 0);
close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
}
else
{
printf("read n = %d\n", n);
write(sockfd, buf, n);
}
if (--nready <= 0)
break;
}
}
}
return 0;
}