【编程】select 网络编程demo

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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值