在C中,我如何访问/迭代动态添加到fd_set的文件描述符?

时间:2018-05-30 08:30:51

标签: c linux

我正在尝试使用select()和fd_sets在C中实现Linux中的服务器/多客户端程序。我正在尝试将从一个连接的客户端发送的消息广播到所有其他连接的客户端,但是一旦动态添加,我就不知道如何访问fd_set中其他客户端的套接字。我试图复制我在C ++中找到的这个实现,但是C中的fd_set没有C ++属性。这是我试图复制的代码:

for(int i = 0; i < master.fd_count; i++)
{
    SOCKET outSock = master.fd_array[i];
    if(outSock != listening && outSock != sock)
    {
        send(outSock, buffer, 250);
    }
}

其中master是fd_set,listening是监听新客户端的原始套接字,sock是要播放的消息来自的套接字。

任何人都可以帮助我学习如何访问fd_set套接字元素,以便能够像在示例中那样对它们进行!=比较。或者,请指出另一种实现多客户端设置的方法,我可以将消息广播回所有连接的客户端。我最初尝试使用带有fork()管道的多进程,但是我找不到关于如何正确实现它的足够信息。

3 个答案:

答案 0 :(得分:1)

在C中,您使用宏FD_ISSET来确定是否设置了给定位。有关详细信息,请参阅manual page for select(2)

基本的想法是,首先您使用FD_ZERO将该设置归零,然后使用FD_SET设置一些位,然后根据select()调用pselect()(或select()味道)。当FD_ISSET返回时,您迭代该集合并使用 <amp-state id="productsState" src="/solrSearchAmp?productCategoryId=14030181&sortResults=customerRating-desc"></amp-state> <amp-state id="product"> <script type="application/json"> { "start":20, "hasMorePages": true } </script> </amp-state> <amp-list src="/solrSearchAmp?productCategoryId=14030181&sortResults=customerRating-desc" [src]="productsState.items" width="320" height="2000" [height]="productsState.items.length * 200" class="m1"> <template type="amp-mustache"> <li class="content navigation ampsiteHeaderNavigation"> <div class="js_eCommerceThumbNailHolder eCommerceThumbNailHolder"> <div class="js_swatchProduct"> <a class="pdpUrl" title="{{name}}" href="{{seoFriendlyUrl}}" id="{{productId}}"> <amp-img alt="{{name}}" title="{{name}}" src="http&#58;&#47;&#47;{{productImageSmallUrl}}" class="productThumbnailImage" height="140" width="170"> </amp-img> </a> </div> </div> </li> <li class="content navigation ampsiteHeaderNavigation"> {{#outOfStock}} <div class="stock">Out Of Stock</div> {{/outOfStock}} <div> <a class="eCommerceProductLink pdpUrl" title="{{name}}" href="{{seoFriendlyUrl}}" id="detailLink_{{productId}}"><span>{{name}}</span></a> </div> </li> <li class="content navigation ampsiteHeaderNavigation"> <div class="js_plpPriceList"> <span><b>&#x20b9;{{listPrice}}</b></span> </div> </li> <li class="content navigation ampsiteHeaderNavigation"> <div class="js_plpPriceSavingPercent"> {{#showPercent}} <span>({{youSavePercent}}% off)</span> {{/showPercent}} </div> </li> <li class="content navigation ampsiteHeaderNavigation"> <div class="js_plpPriceOnline"> <span><b>&#x20b9;{{price}}</b></span> </div> </li> </template> </amp-list> <form method="GET" action="/solrSearchAmp?productCategoryId=14030181&sortResults=customerRating-desc" action-xhr="/solrSearchAmp?productCategoryId=14030181&sortResults=customerRating-desc" target="_top" on="submit-success: AMP.setState({ productsState: { items: productsState.items.concat(event.response.items), }, product:{ start: product.start + 20, hasMorePages: event.response.hasMorePages } });"> <input type="hidden" name="start" value="20" [value]="product.start"> <input type="submit" value="Show more" class="ampstart-btn caps m1 show" [class] = "(product.hasMorePages == false ? 'hide' : 'ampstart-btn caps m1 mb3 show')"> </form> 来确定您是否可以对指定的描述符执行非阻塞I / O操作。

网上有很多例子;例如,an example from IBM

答案 1 :(得分:0)

保留拥有已连接“用户”的列表,例如包含每个用户所需内容的结构的链接列表(如用户名和其他数据)套接字描述符。

然后,如果您需要向所有用户发送消息,只需迭代此列表即可。由于结构包含有关用户的所有信息,因此在迭代时很容易跳过一个或多个用户,例如不发送给发出消息的用户。

简单示例

struct user
{
    char  *name;    // Name of the user
    SOCKET socket;  // Socket descriptor for communication
    // Other data needed for the user...
    struct user *next;  // For linking into a list
};

// The list of all users
struct user *users = NULL;

// Broadcast a message to *all* connected users
void broadcast(const char *message)
{
    for (struct user *u = users; u != NULL; u = u->next)
    {
        send(u->socket, message, strlen(message), 0);
    }
}

// Broadcast to all except a specific user
void broadcast_except_name(const char *message, const char *name)
{
    for (struct user *u = users; u != NULL; u = u->next)
    {
        if (strcmp(u->name, name) != 0)
        {
            send(u->socket, message, strlen(message), 0);
        }
    }
}

// Broadcast to all except a specific socket
void broadcast_except_socket(const char *message, SOCKET socket)
{
    for (struct user *u = users; u != NULL; u = u->next)
    {
        if (u->socket != socket)
        {
            send(u->socket, message, strlen(message), 0);
        }
    }
}

[用于创建或以其他方式操作列表的功能]

答案 2 :(得分:0)

养成阅读联机帮助的习惯。 select(2)的列表列出了为fd_set提供的宏:

   void FD_CLR(int fd, fd_set *set);
   int  FD_ISSET(int fd, fd_set *set);
   void FD_SET(int fd, fd_set *set);
   void FD_ZERO(fd_set *set);

您可以使用FD_SETFD_ISSET宏来设置或测试fd_set中与您的文件描述符对应的位。