2012-11-28 35 views
1

我一直在使用该网站一段时间(本学期后)期待回馈!但是,我最后一次希望得到你的帮助,而其他答案似乎没有任何帮助。背景:使用C++,套接字和客户机/服务器体系结构设计一个基本的聊天室,最多10个客户机与服务器通话。客户端所说的任何东西都会在所有客户端和服务器(除了发送客户端)之间回显。使用C++套接字 - 使用accept()和文件描述符加重错误

问题:错误发生在recv调用中,作为clientTalk函数中的while循环条件。我收到了“接收失败:错误的文件描述符”,但服务器和客户端都没有“完全崩溃”,并且没有发生明显的行为变化,尽管事实上接收到的是完全轰炸。

试图解决:

  • 谷歌和SOF。 2小时...

  • 移动变量,带插座的设置和开放玩弄/关闭

-Valgrind:发生在我的接受声明

==773== Warning: invalid file descriptor 96600128 in syscall read() 

Recieve failed: Bad file descriptor 
==773== Thread 2: 
==773== Conditional jump or move depends on uninitialised value(s) 
==773== at 0x4015A0: ??? (in /nethome/users/ghm455/CS284/ChatServer/server) 
==773== by 0x4E39E99: start_thread (pthread_create.c:308) 
==773== by 0x5442CBC: clone (clone.S:112) 
==773== 
==773== Conditional jump or move depends on uninitialised value(s) 
==773== at 0x401614: ??? (in /nethome/users/ghm455/CS284/ChatServer/server) 
==773== by 0x4E39E99: start_thread (pthread_create.c:308) 
==773== by 0x5442CBC: clone (clone.S:112) 
==773== 
==773== Warning: invalid file descriptor 96600128 in syscall close() 

的第一个警告。接收失败发生在recv上,最后的警告发生在尝试关闭时。这是由遍布整个代码的cout陈述确定的。

CODE:下面。如果您认为错误在那里,我会发布客户端,但是一切都指向这是服务器端问题。

`#define SERVER_PORT 9999  /* define a server port number */ 

using std::cout; 
using std::endl; 
using std::string; 

//Globals - descriptorArray holds client FDs. arraySize is its size. 
//soc holds the information on the server's socket. 
//m is the global mutex shared among the server and all clients 
const int MAX_CLIENT = 10; 
int descriptorArray[MAX_CLIENT]; 
int arraySize = 0; 
int soc; 
pthread_mutex_t m; 

struct thread_info 
{ 
pthread_t threadID; //Stores the ID number returned by pthread_create 
int threadNumber; //We have to number incoming threads correctly 
char *messageSent; //Message taken in from command line 
}; 

int main() 
{ 
void exitHandler(int sig); // Function that handles the control-C 
void* clientTalk(void *arg); // Reads and writes with clients 
struct sockaddr_in server_addr, client_addr; 
int option = 1; 
unsigned int clientCount; 
uint8_t *new_socket; 

//Initialize the socket 
soc = socket(AF_INET, SOCK_STREAM, 0); 
if (soc < 0) 
{ 
    cout << "ERROR : problem opening socket" <<endl; 
    return 1; 
} 

//Create socket structure 
bzero((char *) &server_addr, sizeof(server_addr)); 
server_addr.sin_family = AF_INET; 
server_addr.sin_addr.s_addr = INADDR_ANY; 
server_addr.sin_port = htons(SERVER_PORT); 

//Binding host address 
if (bind(soc, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) 
{ 
    cout << "ERROR : problem occured while binding" <<endl; 
    close(soc); 
    exit(1); 
} 
if(setsockopt(soc, SOL_SOCKET, SO_REUSEADDR, (char*) &option, sizeof(option)) < 0) 
{ 
    printf("setsockopt failed\n"); 
    close(soc); 
    exit(1); 
} 

signal(SIGINT, exitHandler); 
listen(soc, MAX_CLIENT); 

clientCount = sizeof(struct sockaddr_in); 
int clientID; 
//cout << "Z " <<endl; 
while(clientID = accept(soc, (struct sockaddr *) &client_addr, (socklen_t*)&clientCount)) 
{ 
    //printf("A"); 
    if (clientID < 0) 
    { 
     perror("ERROR ON ACCEPT"); 
     exit(1); 
    } 
    else 
    { 
     pthread_t newClient; 
     new_socket = (uint8_t*)malloc(1); 
     *new_socket = clientID; 
     pthread_mutex_lock(&m); 
     if (arraySize < 10) 
     { 
      descriptorArray[arraySize++] = newClient; 
     } 
     else 
     { 
      cout << "There are already 10 clients connected!" << endl; 
     } 
     pthread_mutex_unlock(&m); 
     if(pthread_create(&newClient, NULL, clientTalk, &new_socket) < 0) 
     { 
      perror("ERROR Creating thread"); 
      return 1; 
     } 
     cout << "Assigned!" <<endl; 
     pthread_join(newClient, NULL); 
    } 
} 
close(soc); 
return 0; 
} 

void exitHandler(int sig) 
{ 
sig = sig + 0; //Removing the warning. A clean compile looks a lot nicer. 
for (int i = 0; i < arraySize; i++) 
{ 
    write(descriptorArray[i], "WARNING: Server exiting in ten seconds. End your conversation!", 1000); 
} 
cout << "WARNING: Server exiting in ten seconds. "; 
cout << "End your conversation!" << endl; 
sleep(10f); 
for (int i = 0; i < arraySize; i++) 
{ 
    close(descriptorArray[i]); 
} 
close(soc); 
exit(1); 
} 


void* clientTalk(void* arg) 
{ 
int* myFD = (int*) arg; 
char buffer[2000]; 
read(*myFD, buffer, 20); 
char username[20]; 
//strcpy(username, buffer); // Takes in the username and stores it 
char movableString[2000]; 
int amount_read; 

// for (int i = 0; i < arraySize; i++) 
// { 
    //strcpy(movableString, username); 
// strcat(movableString, " has joined the room!"); 
    //if (descriptorArray[0] != *myFD) 
    //{ 
    // write(descriptorArray[0], movableString, 2000); 
    //} 
//} 
cout << "x" << endl; 
int arrayLocation; 
while ((amount_read = recv(*myFD, buffer, 2000, MSG_WAITALL)) > 0) 
{ 
    cout << " Um" << endl; 
    pthread_mutex_lock(&m); 
    for (int i = 0; i < arraySize; i++) 
    { 
     if (descriptorArray[i] == *myFD) 
     { 
      arrayLocation = i; 
      break; 
     } 
    } 
    strcpy(movableString, username); 
    strcat(movableString, ": "); 
    strcat(movableString, buffer); 
    for (int i = 0; i < arraySize; i++) 
    { 
     //if (i != arrayLocation) 
     //{ 
      write(*myFD, movableString, 2000); 
     //} 
    } 
    pthread_mutex_unlock(&m); 
} 
if (amount_read == 0) 
{ 
    cout << username << "disconnected unexpectedly" <<endl; 
    fflush(stdout); 
} 
if (amount_read == -1) 
{ 
    perror("Recieve failed"); 
} 


pthread_mutex_lock(&m); 
for (int i = 0; i < arraySize; i++) 
{ 
    if (descriptorArray[i] == *myFD) 
    { 
     arrayLocation = i; 
     break; 
    } 
} 

for (int i = arrayLocation; i < arraySize - 1; i++) 
{ 
    descriptorArray[i] = descriptorArray[i + 1]; 
} 
arraySize--; 

pthread_mutex_unlock(&m); 
close(*myFD); 
pthread_exit(NULL); 
free(arg); 
} 

`

我会监视这个网站回答您的任何问题。我提前道歉,在提出问题时犯任何新手错误。

谢谢你的帮助!

+1

当你将套接字传递给你的线程时,你使用'int8_t',它应该是'size_t'(一个指针的大小),而在C++中你应该使用'new'而不是'malloc'。 –

+1

应该是int作为接受的posix定义返回一个int –

+1

对不起,但我停止阅读'行为发生没有明显的变化,尽管事实上,接收轰炸完全'这对我来说根本没有意义 –

回答

1

此错误表示传递给读取函数的文件描述符不是有效的文件描述符,因此调试时首先要确保ClientTalk函数中文件描述符的值与main中的相同。

@ J.N。在评论中是正确的。他们不会是相同的,因为FD是一个i​​nt,并且只是将第一个字节传递给函数(并将其转换为int *指针)。

您可能想用C编写该程序看起来不像C++代码。

  1. 将ClientID和new_socket更改为int/int *。 使用一致的类型,并使用函数定义中的类型接受返回一个int,所以对所有内容使用int/int *。
  2. 当尽可能地调用malloc使用sizeof不是字节数时。

可能还有其他问题。

1

这里至少有两个问题。首先,你永远不会打电话给pthread_mutex_init,这样你的互斥体就不会被创建为一个健全的状态(尽管如果它在全局范围内它将被置零)。

其次,您将&new_socket作为void*传递给您的线程。这是uint8_t**的类型,而在你的clientTalk函数中,你的C风格演员将它转换为int*这是一个完全不同的指针类型,并且肯定不会提供你想要的结果。

相关问题