ARM上Linux的TCP多线程通信(带select函数)例程 - ZYNQ7020学习

       在我的另一篇博客中介绍了Linux下TCP的通信流程以及简单TCP通信实例的实现。在学习网络编程时,经常看到这样一句话:“只有使用了select函数才能写出像样的网络程序”,所以这篇博客分享一个带有select函数实现的TCP多线网络通信。服务器代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <pthread.h>

#define SERVER_PORT			2828	
#define LISENT_NUM			10
#define RECEIVE_LEN			128

//发送线程全局变量
int send_Thread_Run = 1;
int lisent_Thread_Run = 1;
int receive_Thread_Run = 1;

int fdmax = 0;
int Client_index = 0;
int client[LISENT_NUM] = { -1 };

void* lisent_Thread(void * arg)
{
	int sfd, cfd;
	struct sockaddr_in clientaddr;
	struct sockaddr_in serverAddr;
	int size = sizeof(struct sockaddr);

	if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("socket");
		exit(-1);
	}

	memset(&serverAddr, 0, sizeof(struct sockaddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = INADDR_ANY;
	serverAddr.sin_port = htons(SERVER_PORT);

	if (bind(sfd, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr)) == -1)
	{
		perror("bind");
		close(sfd);
		exit(-1);
	}

	if (listen(sfd, LISENT_NUM) == -1)
	{
		perror("listen");
		close(sfd);
		exit(-1);
	}

	printf("Enter into lisent thread, PORT=%d\n", SERVER_PORT);

	while (lisent_Thread_Run)
	{
		if ((cfd = accept(sfd, (struct sockaddr *)&clientaddr, (socklen_t*)&size)) == -1)
		{
			perror("accept");
			close(sfd);
			exit(-1);
		}
		fdmax = fdmax > cfd ? fdmax : cfd;
		printf("client connect success! cfd = %d fdmax = %d\n", cfd, fdmax);

		client[Client_index] = cfd;

		cfd = 0;
		Client_index += 1;

		printf("---client%d (ip = %s : SERVER_PORT = %d) connect success\n", Client_index, inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
	}

	printf("listen thread exit!\n");
}

void* send_Thread(void * arg)
{
	int len, iflag, ret = 1;
	char buff[1024];

	printf("Enter into send thread!\n");

	while (send_Thread_Run)
	{
		int i = 0;
		if ((Client_index > 0) && (Client_index < LISENT_NUM))
		{
			usleep(1000 * 500);
			for (i = 0; i < Client_index; i++)
			{
				if (send(client[i], "hello", 6, MSG_NOSIGNAL) == -1)
				{
					perror("send");
					//if (close(client[i]) >= 0)
					//	printf("---client%d cfd=%d exit ---\n", i + 1, client[i]);
					for (; i < Client_index; i++)
					{
						client[i] = client[i + 1];
					}
					client[Client_index] = -1;
					Client_index -= 1;
				}
			}
		}
	}

	printf("send thread exit!\n");

	for (int i = 0; i < Client_index; i++)
	{
		if (client[i] != -1)
			close(client[i]);
	}
}

void* receive_Thread(void * arg)
{
	int ret = 0, flag = 0;
	char buf[RECEIVE_LEN];
	fd_set fdr;
	struct timeval SelectTimeOut;

	printf("Enter into receive thread!\n");


	while (receive_Thread_Run)
	{
		int selectNum = 0;
		FD_ZERO(&fdr);

		if (Client_index)
		{
			for (int i = 0; i < Client_index; i++)
			{
				if (client[i] > 0)
					FD_SET(client[i], &fdr);
			}
		}

		SelectTimeOut.tv_sec = 5;
		SelectTimeOut.tv_usec = 500;
		//selectNum = select(FD_SETSIZE, &fdr, NULL, NULL, &SelectTimeOut);
		selectNum = select(fdmax + 1, &fdr, NULL, NULL, &SelectTimeOut);

		switch (selectNum)
		{
		case -1:
			printf("selectNum =  %d\n", selectNum);
			perror("select error");
			break;
			//exit(-1);
		case 0:
			continue;
		default:
			printf("selectNum =  %d\n", selectNum);
			for (int i = 0; i < Client_index; i++)
			{
				if (FD_ISSET(client[i], &fdr))
				{
					ret = recv(client[i], buf, sizeof(buf), 0);
					if (ret > 0)
					{
						printf("client%d receive: %s %d\n", i + 1, buf, ret);
					}
					else if (ret == 0)
					{
						if (close(client[i]) >= 0)
						{
							printf("close socket success cfd=%d \n", client[i]);
							FD_CLR(client[i], &fdr);

							for (int j = 0; j < Client_index; j++)
							{
								client[j] = client[j + 1];
							}
							client[Client_index] = -1;
							Client_index -= 1;
							printf("--- Client number = %d client%d exit---\n", Client_index, i + 1);
						}
						else
							printf("close socket failed cfd=%d \n", client[i]);
					}
					else
					{
						perror("recv");
						exit(-1);
					}
					memset(buf, 0, RECEIVE_LEN);
				}
			}
			break;
		}
	}
}



int main(int argc, char * argv[])
{
	int sfd, cfd;
	int iflag, ret;
	struct sockaddr_in clientaddr;
	struct sockaddr_in serverAddr;
	char buff[1024];
	int size = sizeof(struct sockaddr);

	pthread_t	sendThead, lisentThead, receiveThead;

	printf("main:server waiting connect...\n");

	pthread_create(&lisentThead, NULL, lisent_Thread, NULL);
	pthread_create(&sendThead, NULL, send_Thread, NULL);
	pthread_create(&receiveThead, NULL, receive_Thread, NULL);

	while (1)
	{

	}
	printf("main thread exit...\n");
	return 0;
}


       说明一下,select函数主要用来实现服务器的多路监听,所以,这里只给出了服务器的代码。客户端仍然与简单TCP通信中相似,或者优化一下阻塞模式为非阻塞模式即可。

       上述代码已亲测可用,但是这里主线程在启动三个子线程后就自动退出了,将监听线程作为主线程使用更为合理,但这里就不改了,现在手里没有板子,怕影响最后代码的质量。

猜你喜欢

转载自blog.csdn.net/yishuicanhong/article/details/81389880
今日推荐