我使用 pthreads 编写了一个相当简单的 C 聊天服务器。服务器正常工作,客户端使用 telnet 连接到它,然后客户端可以相互通信。每个客户端都在自己的线程中启动。当任何客户端想要断开连接时,就会出现问题。即使我关闭客户端套接字并完成它的线程(它确实如此,或者至少 gdb 是这样说的),这种干扰以某种方式关闭了服务器端的所有通信,即使其他线程仍在运行。在此之后,客户端无法相互通信,从而使服务器变得毫无用处。我不知道如何解决这个问题,我请求你的帮助。谢谢你。
这是我的代码。我包含完整代码,因为我不确定我的错误在哪里
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
int user[30]; // sockets of connected users
char names[30][20];
int user_count=0; // number of active connections
int listen_sock; // main socket, recieves connections
char buffer[500];
pthread_t *thready[30];
pthread_mutex_t mutex;
struct arg_struct {
int arg1;
int arg2;
};
void sending(char *text, int i) {
char buffer2[504];
strcpy(buffer2, "\r\0");
strcat(buffer2, text);
strcat(buffer2, "\r\0");
write(user[i], buffer2, strlen(buffer2));
}
void welcome(int id) {
int len;
int sock;
char name[20];
pthread_mutex_lock(&mutex);
sock = user[id];
write(sock,"\rEnter your name: ", 18);
// Read returns number of characters recieved
len = read(sock,name,20);
// Add zero to the end of string (read doesnt do it)
name[len]='\0';
while (name[len] < 32)
{
name[len]='\0';
len--;
}
// snprintf(buffer,"Welcome %s!\n",name);
write(sock, "Welcome\r\n", 7);
strcpy(names[id], name);
sending(buffer,id);
pthread_mutex_unlock(&mutex);
}
void echo(char *text) {
int i;
for (i=0; i<user_count; i++) {
sending(text, i);
}
}
void disconnect(int id) {
int i;
char deadname[20];
strcpy(deadname,names[id]);
sending("You have been disconnected\n",id);
shutdown(user[id], SHUT_RDWR);
close(user[id]);
for (i=id; i<user_count-1; i++) {
user[i]=user[i+1];
strcpy(names[i],names[i+1]);
}
user_count--;
sprintf(buffer,"%s has disconnected\n",deadname);
echo(buffer);
}
void finish() {
echo("Shuting down, disconnecting everyone!\n");
while (user_count > 0) disconnect(user_count-1);
shutdown(listen_sock, SHUT_RDWR);
close(listen_sock);
pthread_mutex_destroy(&mutex);
exit(0);
}
void getcomm(char *inpstr, char *comm) { /* First letter from inpstr goes to comm,
and is removed from inpstr */
int wpos=0,leng; /* Splits first word from the rest of the sentence */
char *zal;
zal=inpstr;
leng=strlen(zal);
while (*inpstr>32 && wpos<14) {
*comm=*inpstr++;
comm++;
wpos++;
}
inpstr=(char *)memmove(zal,inpstr+1,leng);
*comm='\0';
}
void input(int id) {
}
void* communication(void* par){
int sock = ((int*)par)[0];
int id = ((int*)par)[1];
free((int*)par);
welcome(id);
while(1){
char line[500];
char command[20];
char name2[16];
int len,sock;
// 1. read line from user
len=read(user[id],line,499);
pthread_mutex_lock(&mutex);
line[len]='\0';
if (len == 0) { // User has terminated the connection
continue;
}
while (line[len] < 32) { // Remove special chars
line[len]='\0';
len--;
}
// 2. Get first word
getcomm(line,command);
// 3. Recognise command and execute it
len=strlen(command);
if (strncmp(command,"quit",4) == 0) {
disconnect(id);
pthread_exit(NULL);
}
else if (!strncmp(command,"tell",len)) {
getcomm(line,name2);
sprintf(buffer,"%s tells %s: %s\n", names[id], name2, line);
echo(buffer);
}
else if (!strncmp(command,"shut",len)) {
finish();
}
// 4. Unknown command
else {
sprintf(buffer,"%s tells %s %s\n", names[id], command, line);
echo(buffer);
}
pthread_mutex_unlock(&mutex);
}
}
int main( int argc, char *argv[] ) {
int pid;
struct sockaddr_in bind_addr;
struct sockaddr_in acc_addr;
int size, user_id, i, sel,on;
int port_number;
char * eptr = NULL;
fd_set readmask;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutex_init(&mutex, NULL);
listen_sock = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sock==-1) {
perror("socket()");
pthread_mutex_destroy(&mutex);
exit(-1);
}
on = 1;
if (argc == 1){
perror("Please specify port number");
pthread_mutex_destroy(&mutex);
//exit(0);
}
if (argc == 2){
port_number = (int) strtol(argv[1], &eptr, 10);
if (*eptr != '\0'){
perror("Invalid Port Number!");
pthread_mutex_destroy(&mutex);
exit(-1);
}
}
port_number = 7501;
bind_addr.sin_family = AF_INET;
bind_addr.sin_addr.s_addr = INADDR_ANY;
bind_addr.sin_port = htons(port_number);
size=sizeof(struct sockaddr_in);
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
if (bind(listen_sock, (struct sockaddr *)&bind_addr, size)==-1) {
perror("bind()");
pthread_mutex_destroy(&mutex);
exit(-1);
}
listen(listen_sock, 10);
while(1) {
FD_ZERO(&readmask);
FD_SET(listen_sock, &readmask);
if (FD_ISSET(listen_sock, &readmask)) {
user_id = user_count++;
int * soc = (int*)malloc(2*sizeof(int));
soc[0] = accept(listen_sock,(struct sockaddr *)&acc_addr, &size);
soc[1] = user_id;
pthread_mutex_lock(&mutex);
user[user_id] = soc[0];
pthread_mutex_unlock(&mutex);
if( ( pthread_create( &thready[user_id], NULL, communication, (void*)soc ) ) < 0)
{
perror("could not create thread");
return 1;
}
echo(buffer);
continue;
}
}
pthread_mutex_destroy(&mutex);
return 0;
}