51. 线程-服务端


在最开始实现并发服务端的时候, 最开始想到的办法便是使用多进程, 使每个 TCP 连接对应一个进程; 之后我们又将多进程并发改写成了 IO 复用的方式实现了相同的功能; 但现在唯一没有将服务端改写成线程, 本节就来改写服务端.


线程服务端

在改写成多线程之前, 要对 [线程创建], [线程同步]以及线程终止有所了解才行.


主函数仅仅只是将连接后回射操作交给线程即可 :

int main(int argc, char *argv[]){
	int sockfd, clientfd;
	socklen_t socklen;
	struct sockaddr_in servAddr, cliAddr;
	pthread_t tid;
	
	bzero(&servAddr, sizeof(servAddr));
	servAddr.sin_family = AF_INET;
	servAddr.sin_port = htons(atoi(argv[1]));
	servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	socklen = sizeof(cliAddr);

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
		goto exit;
	if(bind(sockfd, (struct sockaddr* )&servAddr, sizeof(servAddr)) < 0)
		goto exit;

	listen(sockfd, 5);
	
	while(1){
		clientfd = accept(sockfd, (struct sockaddr *)&cliAddr, &socklen);
		if(clientfd < 0)
			goto exit;
        // 将回射功能交给线程
		if(pthread_create(&tid, NULL, echo, (void *)&clientfd))
			goto exit;
	}

exit:
	return 0;
}

线程函数就只是一个简单的回射功能 :

void *echo(void *sockfd){
	// 使线程分离, 退出后直接释放资源
	pthread_detach(pthread_self());

	char buf[BUFSIZE];
	int n;
	int fd = *(int *)sockfd;

	while(1){
		n = read(fd, buf, sizeof(buf));
		if(0 == n) break;
		write(fd, buf, n);
	}
	close(fd);
	
	pthread_exit((void *)0);
}

线程函数中注意需要执行 pthread_detach() 函数来完成线程分离, 这样主进程就可以不执行 pthread_join 阻塞来回收线程的资源, 线程结束后自己回收资源.


服务端完整代码 : service.c

服务端 :

./service 8080

客户端完整代码 : client.c

客服端 :

./client 127.0.0.1 8080

在这里插入图片描述


线程回射程序bug

在前面不管是多进程还是IO复用我们都或多或少遇到过问题, 那么改写成线程也同样会有意想不到的问题.


上面的回射程序有一处很严重的bug.

pthread_create(&tid, NULL, echo, (void *)&clientfd)

我们函数参数传入的是指针, 线程是并发执行, 对于参数 clientfd容易导致同步问题. 如果为每次的clientfd 申请内存, 也会导致函数并非线程安全, 并且频繁的申请也容易导致申请失败同时内存释放也是一个问题.


解决方法 :

  1. 加锁, 保证同步. 但是使用锁运行效率肯定就很低, 反而性能会降低.
  2. 封装函数传入形参或者结构体 . 一般都采用该呢方式, 也有更好的封装和扩展性. 之后可以在线程池[1]中看到.

小结

  • 线程编程注意同步问题.
  • 可以将 web 客户端 的改写成线程, 这样就可以不将 connect 设置成非阻塞.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值