c++ - C/C++ : Write and Read Sockets

标签 c++ c sockets unix

我正在使用 unix 套接字发送和接收信息,但我不完全理解它是如何工作的。基本上,我发送这样的消息:

int wr_bytes = write(sock, msg.c_str(), msg.length());

并接收这样的消息:

int rd_bytes = read(msgsock, buf, SOCKET_BUFFER_SIZE);

这段代码可以完美地处理数千个字节,我不明白的是,read函数如何知道另一部分何时完成发送消息?我尝试阅读 read documentation而且,据我了解,一旦达到 EOFSOCKET_BUFFER_SIZEread 就会返回,这是正确的吗?

所以我猜测,当我将字符串提供给 write 函数时,它会在内容末尾添加一个 EOF ,因此 read 函数知道何时停止。

我问这个问题是因为,我没有添加任何代码来检查另一部分是否完成发送消息,但是,我收到大消息(数千字节)没有任何问题,为什么会发生这种情况,为什么我只收到部分消息?

这是我用来向 unix 套接字服务器发送消息的完整函数:

string sendSocketMessage(string msg) {
    int sock;
    struct sockaddr_un server;
    char buf[1024];

    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sock < 0) {
        throw runtime_error("opening stream socket");
    }
    server.sun_family = AF_UNIX;
    strcpy(server.sun_path, "socket");

    if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
        close(sock);
        throw runtime_error("connecting stream socket");
    }
    if (write(sock, msg.c_str(), msg.length()) < 0){
        throw runtime_error("writing on stream socket");
        close(sock);
    }
    bzero(buf, sizeof(buf));
    int rval = read(sock, buf, 1024);
    return string( reinterpret_cast< char const* >(buf), rval );
}

这是我的服务器函数(稍微复杂一点,vSocketHandler 类型表示我调用来处理请求的函数):

void UnixSocketServer::listenRequests(vSocketHandler requestHandler){
    int sock, msgsock, rval;
    struct sockaddr_un server;
    char buf[SOCKET_BUFFER_SIZE];

    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sock < 0) {
        throw runtime_error("opening stream socket");
    }
    server.sun_family = AF_UNIX;
    strcpy(server.sun_path, SOCKET_FILE_PATH);
    if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) {
        throw runtime_error("binding stream socket");
    }
    listen(sock, SOCKET_MAX_CONNECTIONS);
    while(true) {
        msgsock = accept(sock, 0, 0);
        if (msgsock == -1){
            throw runtime_error("accept socket");
        } else {
            bzero(buf, sizeof(buf));
            if((rval = read(msgsock, buf, SOCKET_BUFFER_SIZE)) < 0)
                throw runtime_error("reading stream message");
            else if (rval == 0){
                //do nothing, client closed socket
                break;
            } else {
                string msg = requestHandler(string( reinterpret_cast< char const* >(buf), rval ));
                if(write(msgsock, msg.c_str(), msg.length()) < 0)
                    throw runtime_error("sending stream message");
            }
            close(msgsock);
        }
    }
    close(sock);
    unlink(SOCKET_FILE_PATH);
}

最佳答案

what I don't understand is, how does the read function knows when the other part is done sending the message?

对于流类型套接字(例如您正在使用的),它不会。对于数据报类型的套接字,通信被分成不同的 block ,但如果一条消息跨越多个数据报,那么答案又是“它不”。这确实是了解 read()write() (以及 send()recv) 的关键事项之一()) 函数的一般情况,以及更具体的关于套接字的信息。

对于这个答案的其余部分,我将重点关注面向流的套接字,因为这就是您正在使用的。我还假设套接字不处于非阻塞模式。如果您打算将通过此类套接字传输的数据分解为不同的消息,那么您需要实现一个应用程序级协议(protocol),通过该协议(protocol)另一端可以识别消息边界。

I tried to read the read documentation and, on my understanding read will return once it reaches EOF or the SOCKET_BUFFER_SIZE, is that correct?

不完全是。 read() 如果到达文件末尾,将会返回,这种情况发生在对等方关闭其套接字(或至少关闭其写入端)时,以便可以肯定不会再发送任何数据。 read() 也会在出现任何各种错误情况时返回。 read() 可能会在其他未指定的情况下返回,只要它至少传输了一个字节。实际上,如果套接字缓冲区已满,通常会调用最后一种情况,但也可能在其他情况下调用,例如缓冲区为空时。

So I'm guessing that when I give my string to the write function, it adds an EOF at the end of my content so the read function knows when to stop.

不,它没有做这样的事情。成功后,write() 函数将发送您要求其发送的部分或全部字节,而不发送任何其他字节。请注意,甚至不能保证发送所有请求的字节;它的返回值告诉您它实际发送了多少个。如果少于“全部”,那么通常您应该简单地执行另一个 write() 来传输其余部分。您可能需要多次执行此操作才能发送整个消息。无论如何,仅发送您指定的字节。

I'm asking this question because, I did not add any code that checks whether the other part finished sending the message, however, I'm receiving big messages (thousands of bytes) without any problem, why is that happening, why am I not getting only parts of the message?

或多或少是因为您很幸运,但您使用 UNIX 域套接字(而不是网络套接字)这一事实会有所帮助。您的数据通过内核非常高效地从发送进程传输到接收进程,并且单个 read() 接收大型 write() 并不特别令人惊讶。然而,您不能安全地依赖这种情况总会发生。

关于c++ - C/C++ : Write and Read Sockets,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56067235/

相关文章:

c++ - 在 vc++ 中获取事件进程名

c++ - 当我的程序崩溃时如何自动生成堆栈跟踪

c++ - 如何在 code::blocks 中更改构建选项?

c - 以下 C 代码段的输出是什么?

c - 如何在c中生成设定范围内具有均匀间隔的随机值

c - 通过 TCP 发送一个整数(C 语言编程)

c++ - 将 ETW 文件对象与 DiskIO 事件关联

指定的初始值设定项可以合法地引用它在 C99 中初始化的变量吗?

c# - UWP 应用程序不从本地主机上的 .NET 桌面应用程序接收 UDP 数据报

java - 如何在Java中读取字节流(PHP/Java套接字通信)