linux网络编程多进程并发服务器

服务器端代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define PORT 			1234
#define MAXSIZE			1024

struct ARG
{
	int connfd;
	struct sockaddr_in clientAddr;
};

void savedata(char *recvbuf, int len, char *cli_data)
{
	static int index = 0;
	int i = 0;

	while (i < len-1)
	{
		cli_data[index++] = recvbuf[i];
		i++;
	}

	cli_data[index] = '\0';
}

static int clientProcess(int connfd, struct sockaddr_in clientSock)
{
	int num = 0;
	int i = 0;
	char recvBuf[MAXSIZE];
	char sendBuf[MAXSIZE];
	char clientName[MAXSIZE];
	char cli_data[MAXSIZE];
	struct timeval val;
	fd_set fd;
	int ret;

	val.tv_sec = 0;
	val.tv_usec = 0;
	
	num = recv(connfd, clientName, MAXSIZE, 0);
	if (num < 0)
	{
		printf("recv clientName message from client!\n");
		return -1;
	}
	clientName[strlen(clientName)-1] = '\0';
	printf("You got's a connection from %s, client name is %s\n",
		inet_ntoa(clientSock.sin_addr), clientName);

	while (1)
	{
		FD_ZERO(&fd);
		FD_SET(connfd, &fd);
		ret = select(FD_SETSIZE, &fd, NULL, NULL, &val);
	
		num = recv(connfd, recvBuf, MAXSIZE, 0);
		if (num == 0)
		{
			printf("Client(%s) closed connection\nUser's data:%s\n",clientName, cli_data);
			close(connfd);
			return -1;
		}
		recvBuf[strlen(recvBuf)-1] = '\0';
		printf("received client (%s) message :%s\n", clientName, recvBuf);

		//保存接收到的信息
		savedata(recvBuf, num, cli_data);

		//将接收到的客户端数据加密返回给客户端
		for (i=0; i='a' && recvBuf[i]<='z') || (recvBuf[i]>='A' && recvBuf[i]<='Z'))
			{
				recvBuf[i] = recvBuf[i] + 3;
				if ((recvBuf[i]>'Z' && recvBuf[i]<'Z'+3) || (recvBuf[i]>'z'))
				{
					recvBuf[i] = recvBuf[i] -26;
				}
			}
			sendBuf[i] = recvBuf[i];
		}
		sendBuf[num-1] = '\0';
		
		send(connfd, sendBuf, MAXSIZE, 0);

		memset(sendBuf, 0, MAXSIZE);
		memset(recvBuf, 0, MAXSIZE);
	}

	close(connfd);
	
	return 1;
}

void *funThread(void *arg)
{
	struct ARG *info;
	info = (struct ARG *)arg;
	
	clientProcess(info->connfd, info->clientAddr);

	free(arg);
	arg = NULL;

	pthread_detach(pthread_self());

	pthread_exit(NULL);
}

int main(int argc, char **argv)
{
	int listenfd, connfd;
	pthread_t pid_t;
	struct ARG *arg;
	struct sockaddr_in serveraddr;
	struct sockaddr_in clientaddr;
	socklen_t len;
	
	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	if (listenfd < 0)
	{
		printf("Creating socket failed!\n");
		return -1;
	}

	int opt = SO_REUSEADDR;
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

	bzero(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(PORT);
	serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);

	if (bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
	{
		printf("bind fails!\n");
		return -1;
	}

	if (listen(listenfd, 5) < 0)
	{
		printf("listen fails!\n");
		return -1;
	}

	len = sizeof(clientaddr);

	for (;;)
	{
		connfd = accept(listenfd, (struct sockaddr *)&clientaddr, &len);
		if (connfd < 0)
		{
			printf("accept fails!\n");
			return -1;
		}

		arg = (struct ARG *)malloc(sizeof(struct ARG));
		if (arg == NULL)
		{
			printf("malloc memory fails!\n");
			return -1;
		}
		memset(arg, 0, sizeof(struct ARG));

		arg->connfd = connfd;
		memcpy((void *)&arg->clientAddr, &clientaddr, sizeof(clientaddr));

		//处理客户端信息
		if (pthread_create(&pid_t, NULL, funThread, (void *)arg) < 0)
		{
			printf("Create thread fails!\n");
			return -1;
		}
	}

	close(listenfd);
}

客户端代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define PORT				1234
#define MAXSIZE 				1024

static int clientProcess(FILE *fp, int connfd)
{
	char readLine[MAXSIZE];
	char recvLine[MAXSIZE];
	int num;

	printf("connect to server success!\n");
	printf("Input client's name:");
	if (fgets(readLine, MAXSIZE, fp) == NULL)
	{
		printf("fgets fails!\n");
		return -1;
	}

	send(connfd, readLine, MAXSIZE, 0);

	while (fgets(readLine, MAXSIZE, fp) != NULL)
	{
		if (strncmp(readLine, "quit", strlen("quit")) == 0)
		{
			fflush(stdin);
			exit(-1);
		}
		
		send(connfd, readLine, strlen(readLine), 0);
		
		num = recv(connfd, recvLine, MAXSIZE, 0);
		if (num < 0)
		{
			printf("received fails!\n");
			return -1;
		}
		recvLine[num-1] = '\0';

		printf("Server message:%s\n", recvLine);
	}

	return 1;
}

int main(int argc, char **argv)
{
	int sockfd;
	struct sockaddr_in serverSock;
	struct hostent *he;

	if (argc != 2)
	{
		printf("Usage: %s \n", argv[0]);
		return -1;
	}

	he = gethostbyname(argv[1]);
	if (he == NULL)
	{
		printf("gethostbyname fails!\n");
		return -1;
	}

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0)
	{
		printf("Create socket fails!\n");
		return -1;
	}

	bzero(&serverSock, sizeof serverSock);
	serverSock.sin_family = AF_INET;
	serverSock.sin_port = htons(PORT);
	serverSock.sin_addr = *((struct in_addr *)he->h_addr);

	if (connect(sockfd, (struct sockaddr *)&serverSock, sizeof serverSock) < 0)
	{
		printf("connect fails!\n");
		return -1;
	}

	clientProcess(stdin, sockfd);

	close(sockfd);
	return 1;
}
编译运行。

首先运行服务器程序,然后打开两个客户端终端并连接上服务器程序。如下图所示:

服务器运行情况:

客户端1运行情况:

客户端2运行情况:


仔细看服务端运行情况就能看到问题,当客户端1退出后,执行

savedata(recvBuf, num, cli_data);
的信息能够打印出来,当客户端2退出时,结果却不打印保存的信息。这是为什么?这就是非线程安全的问题。

你可能感兴趣的:(网络编程,linux操作系统)