非阻塞式Socket之select的DEMO實現

select_server.c

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
//#include <stdbool.h>

#define bool int
#define true 1
#define false 0

#define MYPORT 8888
#define BACKLOG 5    //how many pending connections queue will hold
#define BUF_SIZE 200
int fd_A[BACKLOG];    //accepted connection fd
int conn_amount;      //current connection amount
void showclient()
{
	printf("client amount: %d\n", conn_amount);
}

int main()
{
	int sock_fd, new_fd;  //listen on sock_fd, new connection on new_fd
	struct sockaddr_in server_addr, client_addr;
	socklen_t sin_size;
	int yes = 1, ret, i;
	char buf[BUF_SIZE];
	fd_set fdsr;  //數組宏定義,與文件句柄產生聯繫
	int maxsock;
	struct timeval tv;
	if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)   //創建socket
	{
		perror("socket create error");
		exit(1);
	}

	if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)  //設置socket的屬性,socket關閉後立即收回 用以加強程序的健壯性
	{
		perror("setsockopt error!");
		exit(1);
	}
	server_addr.sin_family = AF_INET;   //地址簇
	server_addr.sin_port = htons(MYPORT);
	server_addr.sin_addr.s_addr = INADDR_ANY;    //自動填充爲本機IP
	memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));

	if ( bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr))== -1)   //綁定
	{
		perror("bind fail!\n");
		exit(1);
	}
	if (listen(sock_fd, BACKLOG))  //開始監聽
	{
		perror("listen fail!\n");
		exit(1);
	}
	printf("listen port %d\n", MYPORT);  //監聽成功
	conn_amount = 0;
	sin_size = sizeof(client_addr);
	maxsock = sock_fd;

	while (true)
	{
		//initialize file descript set 
		FD_ZERO(&fdsr);
		FD_SET(sock_fd, &fdsr);
		tv.tv_sec = 30;
		tv.tv_usec = 0;
		//加入活躍的連接
		for (i = 0; i < BACKLOG; i++)
		{
			if (fd_A[i] != 0)
			{
				FD_SET(fd_A[i], &fdsr);
			}
		}

		ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);
		if (ret < 0)
		{
			perror("select error!\n");
			break;   //退出循環
		}
		else if (ret == 0)
		{
			printf("select timeout!\n");
			continue;      //繼續循環
		}
		//檢查集合內的每個socket連接
		for (i = 0; i < conn_amount; i++)
		{
			if (FD_ISSET(fd_A[i], &fdsr))
			{
				ret = recv(fd_A[i], buf, sizeof(buf), 0);
				if (ret <= 0)             //客戶端關閉
				{
					printf("client[%d] close\n", i);
					close(fd_A[i]);
					FD_CLR(fd_A[i], &fdsr);    //將該文件描述符從文件描述符集中清除
					fd_A[i] = 0;
				}
				else     //輸出接收到的數據
				{
					if (ret < BUF_SIZE)
					{
						memset(&buf[ret], '\0', 1);
					}
					printf("client[%d] send:%s\n", i, buf);
				}
			}
		}

		//檢查是否有新連接接入
		if (FD_ISSET(sock_fd, &fdsr))
		{
			new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
			if (new_fd <= 0)
			{
				perror("accept error!");
				continue;
			}
			//增加至隊列
			if (conn_amount < BACKLOG)
			{
				fd_A[conn_amount++] = new_fd;
				printf("new connection client[%d] %s:%d\n", conn_amount, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
				if (new_fd > maxsock)
				{
					maxsock = new_fd;
				}
			}
			else
			{
				printf("已達到最大連接數,退出\n");
				send(new_fd, "bye", 4, 0);
				close(new_fd);
				break;
			}
		}
		showclient();
	}

	//關閉其他連接
	for (i = 0; i < BACKLOG; i++)
	{
		if (fd_A[i] != 0)
			close(fd_A[i]);
	}
	exit(0);
}

select_client.c

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8888

int main(int argc, char **argv) 
{
	int sock;
	struct sockaddr_in my_addr;
	int len;
	char buf[100];
	char recbuf[100];
	if (argc < 2)
	{
		printf("Usage: %s <message>", argv[0]);
		exit(1);
	}

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("socket create error.\n");
		exit(1);
	}
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(PORT);
	//地址賦值
	if (inet_aton("127.0.0.1",(struct sockaddr *)&my_addr.sin_addr.s_addr) == 0)
	{
		perror("change address error.\n");
		exit(1);
	}

	//連接
	if (connect(sock,(struct sockaddr *)&my_addr, sizeof(struct sockaddr)) < 0)
	{
		perror("connect error.\n");
		exit(1);
	}
	printf("argv[1]:%s,len:%d\n", argv[1], strlen(argv[1]));
	len = send(sock, argv[1], strlen(argv[1]) - 1,0);
	if (len < 0)
	{
		perror("send error.\n");
		exit(1);
	}
	sleep(1);
	close(sock);
}

 

發佈了13 篇原創文章 · 獲贊 5 · 訪問量 1552
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章