簡體   English   中英

帶有C語言套接字的POSIX線程

[英]POSIX Threads with Sockets in C

#include "cs241.c"

#define THREAD_COUNT 10

int list_s;
int connections[THREAD_COUNT];
char space[THREAD_COUNT];

int done = 0;

pthread_mutex_t muxlock = PTHREAD_MUTEX_INITIALIZER;

int *numbers;
int numbers_count;

void *listener(void *arg) {
    int n = *(int *) arg;

    FILE *f = fdopen(connections[n], "r");
    if (f == NULL)
        printf("Could not open file\n");
    char *line = NULL;
    size_t *len = malloc(sizeof(int));
    while(getline(&line, len, f) != -1) {
        printf("%s", line);
        if (strcmp("END", line) == 0) {
                            pthread_mutex_lock(&muxlock);
            done = 1;
            pthread_mutex_unlock(&muxlock);                     
        }
    }

    space[n] = 't';
    fclose(f);
    free(len);
    close(connections[n]);
    return NULL;
}

void initialize() {
    int n;
    for (n = 0; n < THREAD_COUNT; n++) {
        space[n] = 't';
    }
}

int check() {
    int index;
    for (index = 0; index < THREAD_COUNT; index++) {
        if (space[index] == 't') {
            space[index] = 'f';
            return index;
        }
    }
    return 0;
}   

int main(int argc, char *argv[]) {
    int port = 0;
    int binder;
    int lis;
    int i = 0;
    int *j = malloc(sizeof(int));
    initialize();
    pthread_t threads[THREAD_COUNT];

    if ((argc != 2) || (sscanf(argv[1], "%d", &port) != 1)) {
        fprintf(stderr, "Usage: %s [PORT]\n", argv[0]);
        exit(1);
    }

    if (port < 1024) {
        fprintf(stderr, "Port must be greater than 1024\n");
        exit(1);
    }

    // set the initial conditions for the numbers array.
    numbers = malloc(sizeof(int));
    numbers_count = 0;

    struct sockaddr_in servaddr; // socket address structure
    // set all bytes in socket address structure to zero, and fill in the relevant data members
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(port);

    list_s = socket(AF_INET, SOCK_STREAM, 0);
    if (list_s < 0) {
        printf("Could not create socket\n");
        exit(EXIT_FAILURE);
    }
    binder = bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr));
    if (binder < 0) {
        printf("Could not bind socket\n");
        exit(EXIT_FAILURE);
    }
    lis = listen(list_s, SOMAXCONN);
    if (lis < 0) {
        printf("Could not listen on socket\n");
        exit(EXIT_FAILURE);
    }
    SET_NON_BLOCKING(list_s);
    while (done != 1) {
        connections[i] = accept(list_s, NULL, NULL);
        if (connections[i] < 0) {
            if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
                continue;
            printf("Could not accept connection\n");
            exit(EXIT_FAILURE);
        }
        i = check();
        *j = i;
                    SET_BLOCKING(list_s);
        pthread_create(&threads[i], NULL, listener, j);
    }

    // Verify the array.
    //verify(numbers, numbers_count);

    free(j);
    close(list_s);

    exit(EXIT_SUCCESS);

}

所以我在main()中有一個while循環,它應該在'done'= 1時退出。這是由listener()設置的,當它收到'END'時。 第一個問題是,當我在第一次迭代時發送'END'時,while循環不會退出,只有在發送了另一個'END'之后。

我在另一個文件中有兩個宏SET_NON_BLOCKING和SET_BLOCKING用於解鎖和阻塞套接字,因此如果沒有連接,它會等待連接。 下一個問題是當我不使用這些宏時,listener()中的getline()無法讀取從流中輸出的所有內容。 當我使用它們時,它根本無法打開流。

我認為一些問題在於將'j'傳遞給線程,因為當第二個線程啟動時,它會在第一個線程可以從中讀取之前覆蓋'j'。 然而,我已經在這里呆了幾天,無法到達任何地方。 任何幫助將不勝感激。 謝謝!

另外我想問一下我的套接字阻塞和線程鎖定是否在正確的位置?

你可能必須發送兩次END,因為你的主線程在產生監聽器線程后立即阻塞在accept() 由於它在accept()上被阻塞,所以無法看到done == 1

你可以通過保持非阻塞模式來解決這個問題。 如果你這樣做,你可能想睡覺以避免在緊密的循環中旋轉。 另一種選擇是發送信號喚醒接受,使其設置EINTR。

在將連接索引傳遞給偵聽器線程方面,您可能在線程覆蓋該值之間存在競爭。 由於int將需要與void *相同或更少的字節,因此您實際上可以直接傳遞int 例如:

pthread_create(&threads[i], NULL, listener, (void *)i);

然后在聽眾中:

int n = (int)arg;

這是一種黑客行為。 更完整的解決方案是使用malloc為每個線程分配單獨的參數結構。 然后,監聽器線程將負責釋放參數。

struct params *p = malloc(sizeof(struct params));
p.index = i;

pthread_create(&threads[i], NULL, listener, p);

然后在聽眾中:

struct params *p = args;
if (p == NULL) {
  // handle error
  return NULL;
}
int n = p->index;
free(p);

你如何管理connections[]space[]數組似乎有很多問題:

  • 你接受連接到connections[i] ,但你傳遞給listener線程的icheck()返回的那個 - 這可能是一個完全不同的i
  • 每個線程都傳遞一個線程參數的相同地址 - j只分配一次,並且每個線程創建使用相同的分配。 如果兩個或多個線程幾乎同時啟動,您將丟失應該傳遞給其中一些線程的索引。
  • 當它完成時, listener將連接標記為可用(我假設這是space[n] = 't';的意圖space[n] = 't';是),但隨后使用connections[n]來關閉連接。 這些都不是通過任何同步執行的。

其他一些評論:

  • 為什么你在世界上動態分配len
  • 的檢查donemain()while循環應由互斥的保護
  • 我不確定傳輸數據的協議到底是什么,但由於你使用的是getline()我認為它是一組以換行符終止的行。 在這種情況下,請記住getline()文檔中的這些信息:“緩沖區以空值終止,並包含換行符,如果找到了”。 如果"END"行包含換行符, strcmp("END",line)將不返回0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM