C ++ Linux多线程套接字问题

时间:2014-02-13 20:19:43

标签: c++ linux multithreading sockets client

这是朋友发给我的客户代码。我对套接字编程知之甚少。它有点像聊天客户端;将文本发送到服务器,服务器将其发送给所有客户端。我编辑了它,在执行时显示彩色文本,并附有聊天命令的说明。问题是/ ls命令将被识别,暂时不会按预期发送到服务器,但它不会在 else if 语句中执行任何指示。其次,在使用命令或向服务器发送文本后,它不会让我使用命令或再发送文本。我可以打字,但没有任何东西进入服务器,我没有收到典型的例如“收到字节12”消息;除非我使用/ dis命令断开与服务器的连接,但我说它当然是“Received Bytes -1”。任何想法或建议?提前致谢。

我还在底部提供了服务器源,因为有人认为那里存在问题。

客户来源

#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 <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;
}

1 个答案:

答案 0 :(得分:1)

我对您的代码的猜测是,您只是阻止此次通话: bytecount = recv(hsock,buffer,buffer_len,0))== -1

阻塞调用(或同步)是对函数的调用,除非它完成,否则将不会返回,因为你说'嘿它在这个套接字上接收1024个字节',除非找到1024字节或'',否则该函数不会返回eom',如果那个插座是空的,你将在那里永远等待。

有关recv(...)以及如何使其无阻塞的详细信息,请参阅:http://pubs.opengroup.org/onlinepubs/009695399/functions/recv.html

希望这有帮助,我没有运行代码,只是那个电话看起来很可疑。

发布服务器代码后,有一个很大的错误: SocketHandler是你的线程的入口点(它就像你的主进程的'main'),但是它没有循环,你的线程在一次receive-send之后退出,然后没有人在监听那个socket服务器端。您需要将类似客户端中的while循环添加到服务器处理程序中。

此外,为了将来参考,尽量不要将变量命名为“口袋妖怪”,这真的让人分心,让其他人更难猜出该变量应该做什么。