2012-05-28 66 views
1

這是一個.c文件的一部分,該文件包含在每個線程有一個客戶端的tcp服務器 - 客戶端消息服務中;我想在服務器線程中使用select來處理新的傳入連接或正在寫入緩衝區的數據,但是我遇到的問題是我需要套接字文件描述符來處理客戶端和服務器。獲取對一個套接字的文件描述符的訪問

在這部分代碼中,服務器的套接字描述符位於s-> sd中,但我似乎可以在此函數之外訪問它,因爲它返回(套接字)。

我該怎麼辦? (代碼大部分被省略,以使其可讀)

#include <sys/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 

typedef struct { 
    int sd; //id of the socket?? 
    char *ip_addr; 
    int port; 
    } MySocket; 

Socket tcp_passive_open(int port) 
{                      
    MySocket *s = (MySocket *)malloc(sizeof(MySocket)); 
    struct sockaddr_in addr; 
    s->sd = socket(PROTOCOLFAMILY, TYPE, PROTOCOL); 

    memset(&addr, 0, sizeof(struct sockaddr_in)); 
    addr.sin_family = PROTOCOLFAMILY; 
    addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    addr.sin_port = htons(port); 

    if (bind(s->sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { 
    die("tcp_open_server failed(): bind() failed"); 
    } 

    s->port = port; 
    s->ip_addr = NULL; //INADDR_ANY ... 
    return (Socket)s; 
} 

主:

Socket server = tcp_passive_open(PORT); 
FD_SET(SOCKETDESCRIPTOR_SERVER??,&master_socketDescriptors); 
+0

s是一個指針。您嘗試返回結構。而是返回指針(您將需要更改函數的返回類型)。並移除除(struct sockaddr *)之外的所有轉換。什麼是Socket?應該是MySocket? – wildplasser

+0

bedankt wildplasser :)問題是雖然我想嘗試它而不改變tcp_passive_open,但也許這是不可能的。而套接字是一個文件類型:我認爲(它不是結構號)。所以你的解決方案恐怕沒有多大幫助。 – Thomas

+0

爲什麼要返回Socket,而您只需鍵入MySocket typedeffed,malloc()ed並初始化。對我沒有意義。 (IANAB ;-) – wildplasser

回答

2

MySocket::sd是你需要與select()使用的描述符。 socket()accept()均返回套接字描述符,可與select()一起使用。更改tcp_passive_open()返回的MySocket*代替Socket,那麼你的主服務器線程將有權訪問服務器的socket描述符傳遞到select()用於檢測傳入的連接,例如:

#include <sys/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 

typedef struct { 
    int sd; 
    char *ip_addr; 
    int port; 
} MySocket; 

MySocket* tcp_passive_open(int port) { 
    MySocket *s = (MySocket *)malloc(sizeof(MySocket)); 
    if (s == NULL) { 
     die("tcp_open_server failed(): malloc() failed"); 
    } 

    s->sd = socket(PROTOCOLFAMILY, TYPE, PROTOCOL); 
    if (s->sd == -1) { 
     die("tcp_open_server failed(): socket() failed"); 
    } 

    struct sockaddr_in addr; 
    memset(&addr, 0, sizeof(struct sockaddr_in)); 
    addr.sin_family = PROTOCOLFAMILY; 
    addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    addr.sin_port = htons(port); 

    if (bind(s->sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { 
     die("tcp_open_server failed(): bind() failed"); 
    } 

    s->port = port; 
    s->ip_addr = NULL; //INADDR_ANY ... 
    return s; 
} 

MySocket* server = tcp_passive_open(PORT); 
FD_SET(server->sd, &master_socketDescriptors); 

之後,當select()報告服務器套接字掛起的入站連接的連接,調用accept()接受連接,並獲得其socket描述符,那麼你可以分配爲它單獨MySocket

int sd = accept(server->sd, ...); 
if (sd != -1) { 
    MySocket *client = (MySocket*) malloc(sizeof(MySocket)); 
    client->sd = sd; 
    ... 
} 

然後,您可以爲該MySocket創建一個新線程,該線程可以調用select()來根據需要檢測該連接上的入站數據。

+0

thx;我想保留tcp_passive_open,因爲我supposly沒有權限(僅限於.h文件)。請記住「套接字服務器= tcp_passive_open(PORT);」在另一個c文件中,其中包含定義了tcp_passive_open的文件的.h文件。但是我忘了在那個.h文件裏面提到一個聲明:「typedef void * Socket;」也許這可以用來獲取套接字描述符? – Thomas

+0

好的;我解決了它顯然這個套接字可以重新轉換爲MySocket結構使用: \t套接字服務器= tcp_passive_open(PORT); \t MySocket * s =(MySocket *)服務器; printf(「套接字描述符:%d」,s-> sd); 但是我不知道爲什麼它需要轉換爲套接字(或者爲什麼所有的函數都會返回套接字而不是MySocket),但是我會問那些給我這些文件的人。 非常感謝你 – Thomas

+0

典型的封裝實踐。首先編寫代碼的人試圖從外部代碼中隱藏「MySocket」的細節。這就是爲什麼'Socket'映射到普通的'void *'指針的原因。這樣,可以改變MySocket的內容而不影響外部代碼。在這種情況下,該代碼應該公開某種'tcp_accept()'和'tcp_select()'函數,它們將'Socket'作爲輸入並在內部爲您處理套接字描述符。如果代碼沒有這樣的功能,那麼這可能是作者的疏忽或者是草率的編程。 –

相關問題