【问题标题】:Get access to the file descriptor of a socket访问套接字的文件描述符
【发布时间】:2012-05-28 20:47:37
【问题描述】:

这是 .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);

【问题讨论】:

  • s 是一个指针。您尝试返回结构。而是返回指针(您需要更改函数的返回类型)。并删除所有演员表,除了 (struct sockaddr *)。还有什么是Socket?那应该是 MySocket 吗?
  • bedankt wildplasser :) 问题是虽然我想在不更改 tcp_passive_open 的情况下尝试它,但也许这是不可能的。而套接字是一种文件类型:我认为(它不是结构号)。所以你的解决方案恐怕没有多大帮助。
  • 你为什么要返回 Socket,而你只是将类型 MySocket 类型化、malloc() 化并初始化。对我来说毫无意义。 (IANAB;-)
  • 什么是Socket?您的代码中没有它的定义。
  • 它来自套接字 api(编辑:我将添加包含以便清楚)

标签: c sockets


【解决方案1】:

MySocket::sd 是您需要与select() 一起使用的描述符。 socket()accept() 都返回可与select() 一起使用的套接字描述符。更改tcp_passive_open() 以返回MySocket* 而不是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()在服务器socket上报告一个挂起的入站连接连接时,调用accept()接受连接并获取它的socket描述符,然后你可以为它分配一个单独的MySocket

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

然后您可以为该MySocket 创建一个新线程,该线程可以根据需要调用select() 来检测该连接上的入站数据。

【讨论】:

  • 谢谢;我想保留 tcp_passive_open 因为我想没有访问权(仅访问 .h 文件)。记住“Socket server = tcp_passive_open(PORT);”位于另一个 c 文件中,其中包含定义 tcp_passive_open 的文件的 .h 文件。但是我忘了提到那个.h文件里面有一个声明:“typedef void * Socket;”也许这可以用来获取套接字描述符?
  • 好的;我显然解决了这个套接字可以使用以下方法重新转换为 MySocket 结构: Socket server = tcp_passive_open( PORT ); MySocket *s = (MySocket *)server; printf("套接字描述符:%d",s->sd);但是,我不知道为什么需要将其转换为套接字(或者为什么所有函数都返回套接字而不是 MySocket),但我会问给我这些文件的人。非常感谢
  • 典型的封装实践。首先编写代码的人试图从外部代码中隐藏MySocket 的详细信息。这就是为什么Socket 映射到一个普通的void* 指针。这样,MySocket 的内容可以在不影响外部代码的情况下更改。在这种情况下,该代码应该公开某种tcp_accept()tcp_select() 函数,它们将Socket 作为输入并在内部为您处理套接字描述符。如果代码没有这样的功能,那可能是作者的疏忽或只是草率的编程。
  • 不,它确实有这些功能,但我需要选择的套接字描述符;在同一个文件中添加处理这些套接字描述符的函数是否更好?因为对我来说,这使它变得更加复杂
猜你喜欢
  • 1970-01-01
  • 2014-04-25
  • 2012-11-02
  • 1970-01-01
  • 1970-01-01
  • 2011-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多