2014-02-13 104 views
0

這是客戶端的一個朋友的代碼發給我的。我對套接字編程知之甚少。它意味着有點像聊天客戶端;發送文本到服務器和服務器將其發送到所有客戶端。我編輯它在哪裏顯示執行與聊天命令上的指令彩色文本。問題是/ ls命令將被識別並且暫時不會按照預期發送到服務器,但是如果聲明不會執行以外的任何其他指令。其次,使用命令或發送文本到服務器後,它不會讓我使用命令或發送文本了。我可以輸入,但沒有任何內容通過服務器,我也沒有收到典型的例如「接收到的字節12」消息;除了我使用/ dis命令從服務器斷開連接之外,當然我會說「Received Bytes -1」。任何想法或建議?提前致謝。C++ Linux多線程插座問題

我還在底部提供了服務器源,因爲有人認爲那裏存在問題。

客戶端源

#include <fcntl.h> 
#include <string.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <stdio.h> 
#include <netinet/in.h> 
#include <resolv.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <unistd.h> 
#include <string> 
#include <sstream> 
#define ANSI_COLOR_RED  "\x1b[31m" 
#define ANSI_COLOR_GREEN "\x1b[32m" 
#define ANSI_COLOR_YELLOW "\x1b[33m" 
#define ANSI_COLOR_BLUE "\x1b[34m" 
#define ANSI_COLOR_MAGENTA "\x1b[35m" 
#define ANSI_COLOR_CYAN "\x1b[36m" 

#define ANSI_COLOR_BRIGHT "\x1b[1m" 
#define ANSI_COLOR_RESET "\x1b[0m" 

using namespace std; 

int main(int argv, char** argc){ 

    string olr = "Global" ANSI_COLOR_RESET; 
    string help = ANSI_COLOR_CYAN "\n\n/help for a list of commands e.g help\n/ls to list online chat rooms e.g. /ls\n/j namehere to join a chat room. e.g. /j Global\n/p namehere -e codehere to private chat. e flag for encryption;\n\tnot required. e.g. /p Sunny got the dox?\n/tp to toggle receiving private messages or not e.g /tp\n/l codehere to listen for encrypted private messages. Seperate \n\tmultiple codes with a comma (,). e.g. /l 123,1234\n/st to stop listening for any encrypted messages e.g /st\n/c namehere to create a chat room. e.g. /c Journalism\n/clr to clear the screen e.g. /clr\n/dis to disconnect from the server e.g. /dis\n/con to connect to the server e.g. /con\n" ANSI_COLOR_RESET; 
    int host_port= 1604; 
    char* host_name="127.0.0.1"; 

    struct sockaddr_in my_addr; 

    char buffer[1024]; 
    int bytecount; 
    int buffer_len=0; 

    int hsock; 
    int * p_int; 
    int err; 

    hsock = socket(AF_INET, SOCK_STREAM, 0); 
    if(hsock == -1){ 
     printf("Error initializing socket %d\n",errno); 
    } 

    p_int = (int*)malloc(sizeof(int)); 
    *p_int = 1; 

    if((setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1)|| 
     (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1)){ 
     printf("Error setting options %d\n",errno); 
     free(p_int); 
    } 
    free(p_int); 

    my_addr.sin_family = AF_INET ; 
    my_addr.sin_port = htons(host_port); 

    memset(&(my_addr.sin_zero), 0, 8); 
    my_addr.sin_addr.s_addr = inet_addr(host_name); 

    if(connect(hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1){ 
     if((err = errno) != EINPROGRESS){ 
      fprintf(stderr, "Error connecting socket %d\n", errno); 

     } 
    } 
    printf(ANSI_COLOR_MAGENTA "\nOnline Rooms: "); 
    printf(olr.c_str()); 
    printf(help.c_str()); 
    //Now lets do the client related stuff 
    while (true){ 
    buffer_len = 1024; 
    string pokemon; 
    pokemon = "/dis"; 
    memset(buffer, '\0', buffer_len); 
    fgets(buffer, 1024, stdin); 
    buffer[strlen(buffer)-1]='\0'; 
    stringstream ss; 
    string bufferstr; 
    ss << buffer; 
    ss >> bufferstr; 
    if (bufferstr == pokemon){ 
     close(hsock); 
    } 

    else if (bufferstr == "/help"){ 
     printf(help.c_str()); 
    } 

    else if (bufferstr == "/ls"){ 
     printf("Online Rooms: "); 
     printf(olr.c_str()); 
    } 

    else if((bytecount=send(hsock, buffer, strlen(buffer),0))== -1){ 
     fprintf(stderr, "Error sending data %d\n", errno); 
    } 

    //what happens after sent 
    //printf("Sent bytes %d\n", bytecount); 

    if((bytecount = recv(hsock, buffer, buffer_len, 0))== -1){ 
     fprintf(stderr, "Error receiving data %d\n", errno); 
    } 
    printf("Recieved bytes %d\nReceived string \"%s\"\n", bytecount, buffer); 
    } 
    //close(hsock); 

} 

服務器源

#include <fcntl.h> 
#include <string.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <stdio.h> 
#include <netinet/in.h> 
#include <resolv.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <unistd.h> 
#include <pthread.h> 

void* SocketHandler(void*); 

int main(int argv, char** argc){ 

    int host_port= 1604; 

    struct sockaddr_in my_addr; 

    int hsock; 
    int * p_int ; 
    int err; 

    socklen_t addr_size = 0; 
    int* csock; 
    sockaddr_in sadr; 
    pthread_t thread_id=0; 


    hsock = socket(AF_INET, SOCK_STREAM, 0); 
    if(hsock == -1){ 
     printf("Error initializing socket %d\n", errno); 
     // goto FINISH; 
    } 

    p_int = (int*)malloc(sizeof(int)); 
    *p_int = 1; 

    if((setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1)|| 
     (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1)){ 
     printf("Error setting options %d\n", errno); 
     free(p_int); 
     // goto FINISH; 
    } 
    free(p_int); 

    my_addr.sin_family = AF_INET ; 
    my_addr.sin_port = htons(host_port); 

    memset(&(my_addr.sin_zero), 0, 8); 
    my_addr.sin_addr.s_addr = INADDR_ANY ; 

    if(bind(hsock, (sockaddr*)&my_addr, sizeof(my_addr)) == -1){ 
     fprintf(stderr,"Error binding to socket, make sure nothing else is listening on this port %d\n",errno); 
    // goto FINISH; 
    } 
    if(listen(hsock, 10) == -1){ 
     fprintf(stderr, "Error listening %d\n",errno); 
//  goto FINISH; 
    } 

    //Now lets do the server stuff 

    addr_size = sizeof(sockaddr_in); 

    while(true){ 
     printf("waiting for a connection\n"); 
     csock = (int*)malloc(sizeof(int)); 
     if((*csock = accept(hsock, (sockaddr*)&sadr, &addr_size))!= -1){ 
      printf("---------------------\nReceived connection from %s\n",inet_ntoa(sadr.sin_addr)); 
      pthread_create(&thread_id,0,&SocketHandler, (void*)csock); 
      pthread_detach(thread_id); 
     } 
     else{ 
      fprintf(stderr, "Error accepting %d\n", errno); 
     } 
    } 

FINISH: 
; 
} 

void* SocketHandler(void* lp){ 
    int *csock = (int*)lp; 

    char buffer[1024]; 
    char pokemon[3]; 
    int buffer_len = 1024; 
    int bytecount; 

    int ignore; 
    pokemon[0] = '/'; 

    if (buffer[0] == pokemon[0]){ 
     ignore = 1; 
    } else {ignore = 0;} 

    memset(buffer, 0, buffer_len); 
    if((bytecount = recv(*csock, buffer, buffer_len, 0))== -1){ 
     fprintf(stderr, "Error receiving data %d\n", errno); 
     //goto FINISH; 
    } 
    printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer); 
    strcat(buffer, " SERVER ECHO"); 

    if (ignore==0) { 
     if((bytecount = send(*csock, buffer, strlen(buffer), 0))== -1){ 
      fprintf(stderr, "Error sending data %d\n", errno); 
      // goto FINISH; 
     } 
    } 

    printf("Sent bytes %d\n", bytecount); 

//FINISH: 
    // free(csock); 
    //return 0; 
} 

+0

瞭解更多關於[poll(2)](http://man7.org/linux/man-pages/man2/poll.2.html)和[事件循環](http://en.wikipedia.org /維基/ Event_loop)。另請參閱[高級Linux編程](http://advancedlinuxprogramming.com/)。使用'g ++ -Wall -g'(或* gcc -Wall -g'編譯* C *代碼)編譯。學習如何使用'gdb'調試器**。 –

回答

1

從你的代碼我的猜測是,你正好擋住就此致電: BYTECOUNT =的recv( hsock,buffer,buffer_len,0))== -1

阻塞調用(或同步)是對函數的調用,除非它完成,否則將不會返回,因爲您在說'嘿在此套接字上接收1024個字節',函數將不會返回,除非它找到1024個字節或' eom',如果那個插座是空的,你會永遠等到那裏。

有關的recv(...),以及如何使它非阻塞看到進一步的信息:http://pubs.opengroup.org/onlinepubs/009695399/functions/recv.html

希望這有助於我沒有運行代碼,只是調用看似可疑。

當你發佈你的服務器代碼後,出現一個大錯誤: SocketHandler是你的線程的入口點(它就像你的主進程的'main'),但它沒有循環,你的線程退出在一次接收發送之後,然後沒有人正在服務器端監聽該套接字。你需要在客戶端添加一個while循環到你的服務器處理程序。另外,爲了將來的參考,儘量不要命名變量的「口袋妖怪」真的讓人分心,讓其他人更難猜測變量應該做什麼。

+0

我註釋了包含recv調用和其下的兩個打印的聲明。我現在可以使用我的命令了!輸入諸如「Hi」之類的信息後,雖然信息不會再次發送到服務器。對此有何想法? – Danny

+0

這與我的答案的第二部分有關: 您的線程只執行一次'SocketHandler',然後退出(死亡,正在進行),所以每次發送消息時它都會進入套接字,但沒有人正在偵聽在服務器上留言(這是你的線程的工作,現在他已經死了,就像Zed寶貝一樣)。你需要在一段時間內包含線程主函數(true){...}循環,確保線程rec的消息,處理它,做它需要做的事情,然後返回到偵聽新消息。 – Sisnett