2012-11-28 34 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*這是一個完全不同的指針類型,並且肯定不會提供你想要的結果。

相關問題