首页 > 解决方案 > C Socket 服务器未捕获传入连接

问题描述

如标题所示,我在 Linux 上有一个带有服务器和客户端的 C TCP 套接字应用程序。服务器正在 localhost 地址 127.9.0.1 的端口 28000 上侦听连接。有时,客户端“打印一个连接语句”,所以 connect() 已经完成。这让我觉得服务器接受了连接请求。但是,客户端“连接”并在从服务器接收到的第一个数据时“冻结”。但实际上服务器还没有准备好发送数据,所以客户端保持在那个状态。这是随机发生的,并且在重新编译后经常发生。我真的不知道问题出在哪里,因为这只发生在我的电脑上(尝试过本机 Linux、WSL 和 VM),我尝试在另一台电脑上执行并且发生的次数非常少。

我想澄清一下,这不会每次都发生,我让整个系统运行。地址绑定没问题,客户端的connect()和服务器的accept()都可以。例如,关闭电脑并启动,使连接工作。

代码很长(可能有一些错误)并且有一些非常糟糕的代码实践,请不要怪我:

服务器.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;

我只包括了连接部分以及我认为检查代码所需的一些东西,希望有人可以帮助我

感谢您的关注

标签: clinuxsocketstcp

解决方案


推荐阅读