自从开始学linux网络编程后就想写个聊天室,一开始原本打算用多进程的方式来写,可是发觉进程间的通信有点麻烦,而且开销也大,后来想用多线程能不能实现呢,于是便去看了一下linux里线程的用法,实际上只需要知道 pthread_create 就差不多了,于是动手开干,用了两天时间,调试的过程挺痛苦的,一开始打算用纯C来撸,便用简单的数组来存储客户端的连接信息,可是运行时出现了一些很奇怪的问题,不知道是不是访问了临界资源,和线程间的互斥有关等等;奇怪的是,当改用STL的set或map时问题就解决了,但上网搜了下发现STL也不是线程安全的,至于到底是什么问题暂时不想去纠结了,可能是其它一些小细节的错误吧。先贴上代码:
首先是必要的头文件 header.h:
#ifndef __HEADER_H #define __HEADER_H #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <error.h> #include <signal.h> #include <sys/wait.h> #include <assert.h> #include <pthread.h> #define bool int // the 3 lines is for c originally #define true 1 #define false 0 #define PORT 9003 #define BUF_LEN 1024 // 缓冲区大小 #define MAX_CONNECTION 6 // 服务器允许的最大连接数,可自行更改 #define For(i,s,t) for(i = (s); i != (t); ++i) #endif // __HEADER_H
然后是客户端部分 client.cpp,相对来说简单一些:
#include "header.h" // 客户端接收消息的线程函数 void* recv_func(void *args) { char buf[BUF_LEN]; int sock_fd = *(int*)args; while(true) { int n = recv(sock_fd, buf, BUF_LEN, 0); if(n <= 0) break; // 这句很关键,一开始不知道可以用这个来判断通信是否结束,用了其它一些很奇葩的做法来结束并关闭 sock_fd 以避免 CLOSE_WAIT 和 FIN_WAIT2 状态的出现T.T write(STDOUT_FILENO, buf, n); } close(sock_fd); exit(0); } // 客户端和服务端进行通信的处理函数 void process(int sock_fd) { pthread_t td; pthread_create(&td, NULL, recv_func, (void*)&sock_fd); // 新开个线程来接收消息,避免了一读一写的原始模式,一开始竟把它放进 while 循环里面了,泪崩。。。 char buf[BUF_LEN]; while(true) { int n = read(STDIN_FILENO, buf, BUF_LEN); buf[n++] = '