accept() 函数在传递 sockaddr_in 时失败

accept() function fails when passing sockaddr_in

我正在编写一个小服务器来学习线程以及如何处理具有不同结构和类型的指针,但是如果我将 sockaddr_in 结构传递给 accept() 函数,它会失败。该程序稍后应使用“correct/incorrect”数据响应不同的输入,以欺骗脚本小子并浪费他们的时间。 (我知道像 inetsim 这样的东西已经存在,但我的主要目标是用它来学习。)但那是未来的音乐。

在 main 函数的 while 循环中,注释行有效(我认为可以做得更好)但我需要线程函数中的 sockaddr_in 结构,这样我就可以创建包含连接 ip 地址的日志文件其名称。我创建了一个带有客户端连接套接字 fd 和指向结构 sockaddr_in 的指针的结构,因此我可以在线程函数中使用它,但就像我说的那样,accept() 总是以 -1 失败,最终导致分段错误(因为我还没有抓住它,但我知道我以后必须要抓住它)。

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

#define LISTEN_BACKLOG 50
#define MAX_THREADS 100

void *handle_connection(void *args);
void *handle_connectionIP(void *args);


struct handle_connection_argument {
    int conn;
    struct sockaddr_in *peer;
};

int main(int argc, char *argv[])
{
    pthread_t threads[MAX_THREADS];
    int iret[MAX_THREADS];
    int conn[MAX_THREADS];
    for(int i=0; i < MAX_THREADS; i++)
        conn[i] = 0;
    int sock;
    char buf[1000];
    struct sockaddr_in address_info;

    struct handle_connection_argument connections[MAX_THREADS];

    address_info.sin_family = AF_INET;
    address_info.sin_port = htons(80);
    address_info.sin_addr.s_addr = htonl(INADDR_ANY);


    sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock == -1){
        fprintf(stderr, "can not create socket\n");
        exit(EXIT_FAILURE);
    }
    fprintf(stdout, "Created socket %d\n", sock);

    if(bind(sock, (struct sockaddr*)&address_info, sizeof(address_info)) == -1){
        fprintf(stderr, "can not bind to %s\n", address_info.sin_addr.s_addr);
        exit(EXIT_FAILURE);
    }
    fprintf(stdout, "Bind to address %s\n", "0.0.0.0");

    if(listen(sock, LISTEN_BACKLOG) == -1){
        fprintf(stderr, "can not listen on %s\n", "0.0.0.0");
        exit(EXIT_FAILURE);
    }
    fprintf(stdout, "Listening on %s\n", address_info.sin_addr.s_addr);
    int counter = 0;
    while(1){
        //conn[counter] = accept(sock, (struct sockaddr*)NULL, NULL);
        //iret[counter] = pthread_create(&threads[counter], NULL, handle_connection, (void *)&conn[counter]);

        connections[counter].conn = accept(sock, (struct sockaddr*)&connections[counter].peer, NULL);
        iret[counter] = pthread_create(&threads[counter], NULL, handle_connectionIP, (void *)&connections[counter]);

        counter++;
    }
    for(int i=0; i < MAX_THREADS; i++)        //useless because I don't leave the while loop yet?
        pthread_join(threads[counter], NULL);

    sleep(1);
}

void *handle_connectionIP(void *args)
{
    //printf("inside thread function\n");
    int n;      // bytes received
    char *ip;   // pointer for holding ip address from connected client

    int *conn;  // socket for client connection
    struct sockaddr_in *peer;   // sockaddr_in with peer data
    struct handle_connection_argument *connection;  // argument give to handle_connectionIP function
    
    connection = (struct handle_connection_argument *)args;
    conn = &connection->conn;
    printf("%d\n", *conn);
    peer = (struct sockaddr_in*) connection->peer;
    ip = inet_ntoa(peer->sin_addr);

    char buf[1000];
    char filename[20];
    sprintf(filename, "connection%d.log", *conn);

    FILE *file;
    file = fopen(filename, "w");
    //peer_address = inet_ntoa(connection->peer->sin_addr);

    printf("Connection %d from %s is managed by Thread (ID:%ld)\n", *conn, ip, pthread_self());
    while((n = recv(*conn, buf, strlen(buf)-1, 0)) > 0) {
           printf("%s", buf);
           fprintf(file, "%s", buf);
    }
    printf("Connection %d closed.\n", *conn);
    fclose(file);
}

void *handle_connection(void *args)
{
    //printf("inside thread function\n");
    int n;
    int *conn;
    conn = (int *)args;
    char buf[1000];
    char filename[20];
    sprintf(filename, "connection%d.log", *conn);

    FILE *file;
    file = fopen(filename, "w");
    //peer_address = inet_ntoa(connection->peer->sin_addr);

    printf("Connection %d is managed by Thread (ID:%ld)\n", *conn, pthread_self());
    while((n = recv(*conn, buf, strlen(buf)-1, 0)) > 0) {
           printf("%s", buf);
           fprintf(file, "%s", buf);
    }

    printf("Connection %d closed.\n", *conn);
    fclose(file);
    pthread_exit((void *)pthread_self());
}

我尝试了所有方法来更改我访问结构的方式,但我仍然不明白。 我将不胜感激任何改进和解释我在这里做错了什么。还对代码本身进行了改进(我不是说风格,而是最佳实践或者没有很好地实现或处理的东西)

这是我的第一个线程和网络程序。我之前只是写了一些简单的处理文件的东西所以请不要太难 :P

我会 post 这作为评论,但我没有足够的代表。我很确定 accept(),第二个参数应该是您之前定义的网络结构(在本例中为 address_info)。例如:accept(sock, (stuct sockaddr*)&address_info, NULL);

希望这就是您要找的答案!

您没有传递正确类型的参数:

connections[counter].conn = accept(sock,(struct sockaddr*)&connections[counter].peer,NULL);

connections[counter].peer 的类型为 struct sockaddr_in *,因此该变量的地址的类型为 struct sockaddr_in **,这不是函数所期望的类型。

您可以直接传递 peer 成员,但这仍然是一个问题,因为您的指针没有指向任何地方。

更改结构定义,使 peer 不是指针:

struct handle_connection_argument {
    int conn;
    struct sockaddr_in peer;
};

并在线程函数中进行相关更改:

peer = &connection->peer;