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而且,根据我的理解,read 将在达到 EOFSOCKET_BUFFER_SIZE 时返回,对吗?

所以我猜测当我将我的字符串提供给 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() 接收大的 writes() 并不奇怪。但是,您不能安全地依赖总是发生这种情况。

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

相关文章:

sockets - 打开服务器或在网络上使用套接字的 Electron 应用程序

c++ - 如何在 qsqlquery.exec 中读取这个 qtstring

c - 指向变量的指针?

c - 乘法结果为零

c - 在 C 代码中使用库

django - 无法通过 group_send 向 Django channel 发送消息

java - 打印出 ArrayList 的每个元素,不重复元素并再次重新打印

c++ - CS_HREDRAW | CS_VREDRAW 有什么作用?

c++ - 为什么我不能访问静态多态派生类中的 protected 成员?

c++ - 无法关闭仅消息窗口 - C++