C Socket 编程,select() 和 fd_set 的问题

发布于 2024-08-26 20:07:33 字数 3053 浏览 5 评论 0原文

我正在学习用 C 语言进行套接字编程(参考 Beej)。

这是我正在尝试实现的一个简单的多用户聊天服务器: http://pastebin.com/gDzd0WqP

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>

#define MSG_SIZE 1024
#define LISTEN_Q 32

struct sockFDList   {
    int sockFD;
    
    struct sockFDList *next;
};

int main(int argc, char *argv[])    {
    int listenFD, newFD, fdmax, i;      // listenFD for listening, newFD for new connection
    char msg[MSG_SIZE];         // buffer for msg transmit
    struct addrinfo hints, *myAI;       // address info
    struct sockaddr_storage remoteAddr; // store client address
    socklen_t sizeAddr;         // sizeof client address
    fd_set masterSet, readSet;      // FD sets for list and read.
    
    // Clear Sets
    FD_ZERO(&masterSet);
    FD_ZERO(&readSet);
    
    // Clear hints
    memset(&hints, 0, sizeof hints);

    // Prep hints
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    // Get local addr info
    getaddrinfo("localhost", argv[1], &hints, &myAI);

    // Get socket for listening
    listenFD = socket(myAI->ai_family, myAI->ai_socktype, myAI->ai_protocol);

    // Bind socket sockFD
    bind(listenFD, myAI->ai_addr, myAI->ai_addrlen);
    
    // Add sfd to master set
    FD_SET(listenFD, &masterSet);
    
    // Initialize fdmax
    fdmax = listenFD;
    
    
    while(1)    {
        // Copy master
        readSet = masterSet;
        
        // call select
        if(select(fdmax+1, &readSet, NULL, NULL, NULL) == -1)
            continue;
        
        // loop through readSet
        for(i=0; i<=fdmax; i++) {
            if(FD_ISSET(i, &readSet))   {   // Active !
                if(i == listenFD)   {   // If listener socket
                    // New Connection, accept
                    sizeAddr = sizeof remoteAddr;
                    newFD = accept(listenFD, (struct sockaddr *)&remoteAddr, &sizeAddr);
                    printf("\n");                   
                    
                    // Add this connection to my master list
                    FD_SET(newFD, &masterSet);

                    // update fdmax
                    if(newFD > fdmax)
                        fdmax = newFD;      
                }
                else    {
                    // Something to read on a socket
                    recv(i, msg, MSG_SIZE, 0);
                    msg[MSG_SIZE] = '\0';       

                    // print it.
                    printf("%s\n",msg);
                }
            }
        }   
    }
    

    return 0;
}

在运行时,它给出总线错误。它来自第 68-78 行。

帮我追查问题的根源吗?

事实上,为什么我的代码甚至到达了那个特定区域?我刚刚运行了服务器。没有客户端连接..:@

ps - 我知道我的代码非常不可靠(任何地方都没有错误检查),但我会在稍后阶段这样做;我只是想在实现它的全部荣耀之前测试代码的功能;)

I'm learning my way about socket programming in C (referring to Beej).

Here is a simple multi-user chat server i'm trying to implement:
http://pastebin.com/gDzd0WqP

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>

#define MSG_SIZE 1024
#define LISTEN_Q 32

struct sockFDList   {
    int sockFD;
    
    struct sockFDList *next;
};

int main(int argc, char *argv[])    {
    int listenFD, newFD, fdmax, i;      // listenFD for listening, newFD for new connection
    char msg[MSG_SIZE];         // buffer for msg transmit
    struct addrinfo hints, *myAI;       // address info
    struct sockaddr_storage remoteAddr; // store client address
    socklen_t sizeAddr;         // sizeof client address
    fd_set masterSet, readSet;      // FD sets for list and read.
    
    // Clear Sets
    FD_ZERO(&masterSet);
    FD_ZERO(&readSet);
    
    // Clear hints
    memset(&hints, 0, sizeof hints);

    // Prep hints
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    // Get local addr info
    getaddrinfo("localhost", argv[1], &hints, &myAI);

    // Get socket for listening
    listenFD = socket(myAI->ai_family, myAI->ai_socktype, myAI->ai_protocol);

    // Bind socket sockFD
    bind(listenFD, myAI->ai_addr, myAI->ai_addrlen);
    
    // Add sfd to master set
    FD_SET(listenFD, &masterSet);
    
    // Initialize fdmax
    fdmax = listenFD;
    
    
    while(1)    {
        // Copy master
        readSet = masterSet;
        
        // call select
        if(select(fdmax+1, &readSet, NULL, NULL, NULL) == -1)
            continue;
        
        // loop through readSet
        for(i=0; i<=fdmax; i++) {
            if(FD_ISSET(i, &readSet))   {   // Active !
                if(i == listenFD)   {   // If listener socket
                    // New Connection, accept
                    sizeAddr = sizeof remoteAddr;
                    newFD = accept(listenFD, (struct sockaddr *)&remoteAddr, &sizeAddr);
                    printf("\n");                   
                    
                    // Add this connection to my master list
                    FD_SET(newFD, &masterSet);

                    // update fdmax
                    if(newFD > fdmax)
                        fdmax = newFD;      
                }
                else    {
                    // Something to read on a socket
                    recv(i, msg, MSG_SIZE, 0);
                    msg[MSG_SIZE] = '\0';       

                    // print it.
                    printf("%s\n",msg);
                }
            }
        }   
    }
    

    return 0;
}

On runtime, it gives Bus Error. It's coming from the lines 68-78.

Help me trace the source of the problem?

in fact, WHY is my code even REACHING that particular region? I've just run the server. no clients have connected.. :@

ps - I know my code is highly unreliable (no error checks anywhere), but I WILL do that at a later stage; I just want to TEST the functionality of the code before implementing it in all it's glory ;)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

美人迟暮 2024-09-02 20:07:33

第 81 行

msg[MSG_SIZE] = '\0';` 

超出了你的缓冲区。 你还需要

msg[MSG_SIZE - 1] = '\0';` 

检查所有可能失败的调用的返回值,即第39、42、45、68和80行

编辑:如果你检查了错误,很可能你' d 看到accept() 调用失败,可能是由于套接字未处于监听模式 - 也就是说,您错过了对listen() 的调用

line 81

msg[MSG_SIZE] = '\0';` 

overruns your buffer. Make it

msg[MSG_SIZE - 1] = '\0';` 

You also need to check the return value of all the calls that can fail, that's line 39,42,45,68 and 80

Edit: And if you'd checked for errors, likely you'd seen the accept() call fail, likely due to the socket not being in listen mode - that is, you're missing a call to listen()

始终不够爱げ你 2024-09-02 20:07:33

另一件需要考虑的事情是,您不一定可以通过简单的赋值来复制 fd_set 变量。处理它们的唯一可移植方法是通过每次循环活动文件描述符列表来从头开始重新生成fd_set

Another thing to consider is that you can't necessarily copy fd_set variables by simple assignment. The only portable way to handle them is to regenerate the fd_set from scratch by looping over a list of active file descriptors each time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文