как в заголовке, у меня есть C приложение сокета TCP с сервером и клиентом на Linux. Сервер прослушивает соединение через порт 28000 по адресу localhost 127.9.0.1. Иногда случается, что клиент «печатает оператор соединения», так что connect () был выполнен. Это заставляет меня думать, что сервер принял запрос на подключение. Однако клиент «подключается» и при первом получении данных с сервера «зависает». Но на самом деле сервер не готов к отправке данных, поэтому клиент остается в этом состоянии. Это происходит случайно и часто после перекомпиляции. Я действительно не знаю, где может быть проблема, так как это происходит только с моим p c (попробовал родной Linux, WSL и VM), я попытался выполнить на другом P C и происходит ОЧЕНЬ реже.
Я хочу уточнить, что это происходит не каждый раз, я заставил всю систему работать. Привязка адреса в порядке, connect () на клиенте и accept () на сервере в порядке. Например, закрытие p c и загрузка заставили соединение работать.
Код довольно длинный (возможно, с некоторыми ошибками) и имеет очень плохую практику кода, пожалуйста, не вините меня:
сервер. c
#include "Client_List.h"
#define BACKLOG 10
typedef struct _t_args_comm
{
user* a;
user* b;
}COMMUNICATION;
bool debug = true;
int socket_ds;
clientNode *Clientlist;
void* ConnectionHandler(void*);
void getClientList(clientNode*, char**, int);
void desc_init(clientNode*, struct pollfd*);
void* Lobby();
void SIGINT_handler(int);
void ErrorServer(const char*, bool);
int main(int argc, char** argv)
{
if(argc == 2)
{
if(strcmp(argv[1], "true") == 0)
debug = true;
else
{
printf("Wrong parameter, Usage: ./server [true], exiting from the program\n");
exit(-1);
}
}
int res, connect_index, client_sock_ds;
socklen_t clientLength;
struct sockaddr_in serv_addr;
struct sockaddr_in client_addr;
char check[32];
pthread_t lobby_tid;
struct sigaction sig;
sigset_t set;
sigaddset(&set, SIGINT);
sig.sa_mask = set;
sig.sa_handler = SIGINT_handler;
// Opening a TCP socket using IP_V4
if((socket_ds = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
ErrorServer("socket open", true);
printf("[+] Server socket is created!\n");
// Setting up the sockaddr_in struct that will store server's address's informations
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT_NUMBER); // to byte order conversion;
// Binding ip address to the socket
if(inet_pton(AF_INET, "127.0.0.1", &(serv_addr.sin_addr)) <= 0)
ErrorServer("inet_pton()", true);
// Binding the server address to the socket
if(bind(socket_ds, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
ErrorServer("bind", true);
// Setting up backlog
if(listen(socket_ds, BACKLOG) == -1)
ErrorServer("listen", true);
printf("[+] Server is waiting for incoming connections...\n");
printf("-------------------------------------------------\n");
user tmpCli;
//Starting lobby's thread
if(pthread_create(&lobby_tid, NULL, Lobby, NULL) == -1)
ErrorServer("pthread_create()", true);
if(sigaction(SIGINT, &sig, NULL) == -1)
ErrorServer("changing SIGINT handler", false);
for(int i = 0; i < 2; ++i){
printf("Listening...\n");
while((client_sock_ds = accept(socket_ds, (struct sockaddr*)&client_addr, &clientLength)) == -1);
printf("[+] --------- New client connected ---------\n");
// Receiving username
do{
if((res =recv(client_sock_ds, tmpCli.username, (size_t)MAX_USERNAME_DIM, 0)) == -1)
ErrorServer("recv() username",true);
tmpCli.username[MAX_USERNAME_DIM-1] = '\0';
if(debug)
printf("username received : %s\n", tmpCli.username);
if(getClientByName(&Clientlist, tmpCli.username) != NULL){
printf("Username already taken\n");
strcpy(check, "there is");
}else{
printf("Valid username\n");
strcpy(check, "there isn't");
}
send(client_sock_ds, check, sizeof(check), 0);
}while(strcmp(check, "there is") == 0);
tmpCli.client_address = client_addr;
tmpCli.client_ds = client_sock_ds;
tmpCli.status = true;
insertClient(&Clientlist, tmpCli);
// Send new user struct to thread lobby to handle connection requests
}
// For the moment i'm handling connections here...
pthread_join(lobby_tid, NULL);
printf("I'am exiting!\n");
exit(0);
}
клиент. c
#include "Client_List.h"
void Talk(char *);
void *ThreadWorks(void * arg);
void SIGINT_handler();
bool debug = true;
bool quit = false;
int socket_ds;
int main(int argc, char** argv){
int res;
struct sockaddr_in serv_addr;
char check[32];
char buff[MAX_MSG_DIM];
char username[MAX_USERNAME_DIM];
char ipAddr[24];
char choose[MAX_USERNAME_DIM];
struct sigaction sig;
sigset_t set;
sigaddset(&set, SIGINT);
sigaddset(&set, SIGUSR1);
sig.sa_mask = set;
sig.sa_handler = SIGINT_handler;
// Opening a TCP socket using IP_V4
if((socket_ds = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
Error("socket()", true);
printf("[+] Client socket is created!\n");
/*
if(sigprocmask(SIG_UNBLOCK, &set, NULL) == -1)
Error("sigprocmask()", true);
*/
if(sigaction(SIGINT, &sig, NULL) == -1)
Error("sigaction() sigint", true);
if(sigaction(SIGUSR1, &sig, NULL) == -1)
Error("sigaction(), sigusr1", true);
// Setting up struct sockaddr
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT_NUMBER); // to network byte order conversion
if(inet_pton(AF_INET, "127.0.0.1", &(serv_addr.sin_addr)) <= 0) // Address of the server to connec
t to!
Error("inet_pton", true);
// binding the server address to the socket
do{
if((res = connect(socket_ds, (struct sockaddr*)&serv_addr, sizeof(serv_addr))) == -1)
Error("connect", false);
sleep(2);
}while(res != 0);
if(inet_ntop(AF_INET, &(serv_addr.sin_addr), ipAddr, 24) == NULL)
Error("inet_ntop", true);
printf("[+] Connected to the server with address %s\n", ipAddr);
// Sending username
do{
printf("[+] Insert your username: ");
scanf("%s", username);
send(socket_ds, username, MAX_USERNAME_DIM, 0);
if(recv(socket_ds, check, sizeof(check), 0) < 0)
printf("[-] Error during receiving data!\n");
if(strcmp(check, "there is") == 0)
printf("This username already exists!\n");
}while(strcmp(check, "there is") == 0);
printf("[+] Username accept!\n");
Client_List. h
Список клиентов - это файл, который содержит реализацию связанного списка и имеет объявления переменных. Вот только часть переменных:
/* Client_List.h*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/socket.h> // For socket things
#include <sys/unistd.h>
#include <netinet/ip.h> // For IPPROTO_xxxx
#include <netinet/in.h> // For bzero and sockaddr_in
#include <arpa/inet.h> // For inet_ntoa and inet_aton
#include <poll.h>
#define MAX_MSG_DIM 1024
#define MAX_USERNAME_DIM 64
#define MAX_USERS 30
#define PORT_NUMBER 28000
#define fflush(stdin) {while(getchar() != '\n');}
#define CONNECTION_REQUEST(usr) strcat("I want to connect to: " #usr);
#define ERR_USERNAME_TAKEN "This username is already been taken"
#define END_USERSLIST "END"
typedef struct us{
long client_ds;
struct sockaddr_in client_address;
char username[MAX_USERNAME_DIM];
bool status;
}user;
typedef struct clientNode{
user client;
int index;
struct clientNode *next;
}clientNode;
Я включил только часть соединения плюс некоторые вещи, которые, я думаю, необходимы для проверки кода, надеюсь, кто-нибудь может мне помочь
Спасибо за ваше внимание