网络编程:服务器模型-并发服务器-多线程实现并发服务器

思想:

主进程专门用于连接多个客户端的请求,若有一条客户端连接进来,主进程就创建一个子进程,用该子进程来处理客户端的业务数据。

tcp_server.c 

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>//sockaddr_in
#include <unistd.h>
#include <arpa/inet.h>   // 包含 inet_addr 函数的声明 
#include <pthread.h>
#define BUF_SIZE 20

void *ThreadFunc(void *arg)
{
	int iClient = *(int *)arg;

	char buf[BUF_SIZE] = {0};

	int ret = -1;

	while(1){
		ret = recv(iClient, buf, BUF_SIZE, 0);
		if(ret <= 0){
			printf("recv error!\r\n");
			close(iClient);
			pthread_exit("thread exit");
		}
		printf("server recv data:%s\r\n",buf);
		//send
		send(iClient, buf, BUF_SIZE, 0);
	}
}

int main(int argc, const char *argv[])
{
	//1.socket
	int iServer = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == iServer){
		puts("----------1、create socket error!----------");
		return -1;
	}
	puts("----------1、create socket ok!----------");

	//2.bind
	struct sockaddr_in stServer;
	stServer.sin_family = AF_INET;//第一个成员
	stServer.sin_port = htons(8888);//第二个成员
	stServer.sin_addr.s_addr = inet_addr("127.0.0.1");//将点分十进制ip地址转换为32位无符号整数
	int ret = bind(iServer, (struct sockaddr *)&stServer, sizeof(struct sockaddr));
	if(-1 == ret){
		puts("----------2、bind error!----------");
		return -1;
	}
	puts("----------2、bind ok!----------");
	
	//3.listen
	ret = listen(iServer, 5);
	if(-1 == ret){
		puts("----------3、listen error!----------");
		return -1;
	}
	puts("----------3、listen ok!----------");

	//4.accept
		//函数原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
		//函数作用:接收客户端的连接请求
		//参数1:文件描述符 ---> socket的返回值
		//参数2:指向存放对方主机信息结构体的指针
		//参数3:指向struct sockaddr大小的指针
		//返回值:成功返回 新的文件描述符 ---> 标识一个新的网络软通道 --->
		//用做收发正文数据(recv/send), 失败 -1
	struct sockaddr_in stClient;//存放对方的主机信息
	socklen_t len = sizeof(struct sockaddr_in);
	char buf[BUF_SIZE] = {0};
	while(1){
		memset(buf, 0, BUF_SIZE);
		int iClient = accept(iServer, (struct sockaddr *)&stClient, &len);
		if(-1 == iClient){
			continue;//当前客户端出错转向下一个客户端	
		}
		printf("----------4、accept ok! iClient = %d\r\n----------",iClient );//标准输入输出出错,所以下一个打开的文件一定是4
		// \r\n适用于所有操作系统,此考虑系统移植
		
		//thread
		pthread_t tID = -1;
		if(0 != pthread_create(&tID, NULL, ThreadFunc, &iClient)){
			perror("create thread error");
			close(iClient);
			continue;
		}
		printf("create thread ok! iClient:%d\r\n",iClient);
	}

	
	return 0;
}

tcp_client.c 

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




#define BUF_SIZE 20
//main函数参数,如果需要键入IP则给定即可
int main(int argc, const char *argv[])
{
	//1、socket
	int iClient = 	socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == iClient){
		puts("----------1、create socket error!");
		return -1;
	}
	puts("----------1、create socket ok!");

	//2、connect
	struct sockaddr_in stServer;
	stServer.sin_family = AF_INET;
	stServer.sin_port = htons(8888);
	//stServer.sin_addr.s_addr = inet_addr("192.168.15.71");
	stServer.sin_addr.s_addr = inet_addr("127.0.0.1");
	int ret = connect(iClient, (struct sockaddr *)&stServer, sizeof(struct sockaddr_in));
	if(-1 == ret){
		puts("----------2、connect error!");
		return -1;
	}
	puts("----------2、connect ok!");

	char buf[BUF_SIZE] = {0};
	while(1){
		//gets();
		//char *fgets(char *s, int size, FILE *stream);
		fgets(buf, BUF_SIZE, stdin);//更安全,边界检查

		//3、send recv
		ret = send(iClient, buf, BUF_SIZE, 0);
		if(-1 == ret){
			puts("----------3、send data error!");
		}
		printf("----------3、send data ok! buf = %s\r\n",buf);

		//recv
		//函数原型:ssize_t recv(int sockfd, void *buf, size_t len, int flags);
		memset(buf, 0, BUF_SIZE);
		ret = recv(iClient, buf, BUF_SIZE, 0);
		if(-1 == ret){
			puts("----------4、recv error!");
			return -1;
		}
		printf("----------4、recv data ok! buf = %s\r\n",buf);
	}
	//close(iClient);

	return 0;
}

运行效果图如下👇

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值