Многопоточный сокет C ++ в Linux [закрыт]

0

Это код клиента, которого прислал мне друг. У меня мало знаний о программировании сокетов. Он должен быть как клиент чата; отправляет текст на сервер, а сервер отправляет его всем клиентам. Я отредактировал его, где отображается цветной текст при исполнении с инструкциями в командах чата. Проблемы в том, что команда /ls будет распознана и не будет отправляться на сервер, как предполагалось на данный момент, но она не сделает ничего, что указано в инструкции else if. Во-вторых, после использования команды или отправки текста на сервер он не позволит мне использовать команду или отправить текст. Я могу печатать, но ничего не происходит на сервере, и я не получаю типичное сообщение "Received bytes 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 eg help\n/ls to list online chat rooms eg/ls\n/j namehere to join a chat room. eg/j Global\n/p namehere -e codehere to private chat. e flag for encryption;\n\tnot required. eg/p Sunny got the dox?\n/tp to toggle receiving private messages or not eg/tp\n/l codehere to listen for encrypted private messages. Seperate \n\tmultiple codes with a comma (,). eg/l 123,1234\n/st to stop listening for any encrypted messages eg/st\n/c namehere to create a chat room. eg/c Journalism\n/clr to clear the screen eg/clr\n/dis to disconnect from the server eg/dis\n/con to connect to the server eg/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; } в #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; }

Теги:
multithreading
sockets
client

1 ответ

1
Лучший ответ

Мое предположение из вашего кода заключается в том, что вы просто блокируете этот вызов: bytecount = recv (hsock, buffer, buffer_len, 0)) == -1

Блокирующий вызов (или синхронный) является вызовом функции, который не будет возвращаться, если он не будет завершен, так как вы говорите "да, он принимает 1024 байта в этом сокете", функция не вернется, если не найдет 1024 байта или "eom", если этот сокет пуст, вы будете ждать его навсегда.

Для получения дополнительной информации о recv (...) и о том, как сделать ее неблокирующей, см. Http://pubs.opengroup.org/onlinepubs/009695399/functions/recv.html.

Надеюсь, это поможет, я не запускал код, просто этот вызов кажется подозрительным.

После того, как вы разместили свой код сервера, есть большая ошибка: SocketHandler - это точка входа для вашего потока (он похож на "основной" вашего основного процесса), но в нем нет цикла, ваш поток выходит после одного приема-отправки и тогда никто не слушает этот сокет на стороне сервера. Вам нужно добавить цикл while, как тот, который находится в клиенте, к вашему обработчику сервера.

Кроме того, для дальнейшего использования, попробуйте не называть "pokemon" ваших переменных, это действительно отвлекает и затрудняет для других людей догадываться, что должна делать эта переменная.

  • 0
    Я прокомментировал заявление if, включая вызов recv и два отпечатка под ним. Теперь я могу нормально пользоваться своими командами! После ввода чего-то типа «Привет», хотя информация больше не будет отправляться на сервер. Есть идеи по этому поводу?
  • 0
    Это связано со второй частью моего ответа: ваш поток выполняет SocketHandler только один раз, а затем завершает работу (умирает, собирается капать), поэтому каждый раз, когда вы отправляете сообщение, оно попадает в сокет, но никто не слушает этого сообщение на сервере (это была работа вашего потока, и теперь он мертв, как Zed baby). Вам необходимо заключить функцию main потока в цикл while (true) {...}, чтобы быть уверенным, что поток записывает сообщение, обрабатывает его, делает все, что ему нужно, а затем возвращается к прослушиванию новых сообщений.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню