繁体   English   中英

C:AF_UNIX套接字上的剩余字节

[英]C: Remaining bytes on AF_UNIX socket

我在AF_UNIX套接字通信中遇到了一些问题,因为在写入数据缓冲区后,似乎还有一些挂起的字节要读取,但我不知道它们来自何处。

我正在用C编写一个多线程服务器程序,该程序通过AF_UNIX套接字与客户端通信,它必须实现一个简单的聊天室。 除其他外,服务器必须在客户端和服务器之间实现文件传输,当我尝试从服务器向客户端发送相当大的文件(269K)时遇到了问题。 (使用较小的文件,我没有任何问题)

对于文件传输,我使用mmap()函数,该函数返回指向要发送的文件的映射的指针,然后使用write()在与必须接收该文件的客户端链接的套接字上写入该数据。 调用write()之后,我检查返回的值是否等于文件大小。 (始终已验证)

客户端在接收到文件后,检查读取数据的大小(总是经过验证)并开始等待其他消息,以便它调用阻塞的read() 是我发现错误的地方,因为客户端读取的内容不应该存在, 就好像套接字上还有剩余的内容要读取 我已经调试了这部分(服务器和客户端)两天了,但我还无法理解问题的根源。

我确定没有其他线程同时在同一套接字上写入

你们中的任何人是否知道此错误的原因是什么?

我尝试以正常的操作顺序发布一些有用的代码思考:

首先是消息结构:

struct message_hdr
{
    op_t     op; 
    char sender[MAX_NAME_LENGTH+1];
};

struct message_data_hdr{
    char receiver[MAX_NAME_LENGTH+1];
    unsigned int   len;
};

struct message_data
{
    message_data_hdr_t hdr;
    char *buf;
};

struct message
{
    message_hdr_t  hdr;
    message_data_t data;
};

服务器到客户端文件的传输从服务器开始,服务器将message_hdr_t发送给正在等待read()的客户端(客户端希望仅接收message_hdr_t )。

int sendHeader(long fd, message_hdr_t* hdr)
{
    if(hdr == NULL || fd < 0) {errno = EINVAL; return -1;}

    int test;
    struct iovec iov;

    iov.iov_base = hdr;
    iov.iov_len = sizeof(message_hdr_t);

    test = writev(fd, &iov, 1);

    return  test;
}

客户端从操作代码( message.hdr.op )得知这是文件类型的消息,并且开始等待文件,

因此服务器发送它:

int sendData(long fd, message_data_t *msg)
{
    if(msg == NULL || fd < 0) {errno = EINVAL; return -1;}

    int test;
    struct iovec iov;

    iov.iov_base = &(msg->hdr);
    iov.iov_len = sizeof(message_data_hdr_t);

    test = writev(fd, &(iov), 1);
    if(test == -1){return -1;}

    if (msg->hdr.len != 0)
    {
        test = write(fd, msg->buf, msg->hdr.len);
        if(test <= 0)
            return -1;
    }

    return test;
}

和客户阅读:

int readData(long fd, message_data_t *data)
{
    if(data == NULL || fd < 0) {errno = EINVAL; return -1;}

    int test;
    struct iovec iov;

    iov.iov_base = &(data->hdr);
    iov.iov_len = sizeof(message_data_hdr_t);

    test = readv(fd, &iov, 1);
    if(test <= 0){return -1;}

    if(data->hdr.len != 0)
    {
        data->buf = malloc(data->hdr.len);
        if(data->buf == NULL){return -1;}

        test = read(fd, data->buf, data->hdr.len);
        if((unsigned int)test != data->hdr.len)
            return -1;
    }

    return test;
}

此时,客户端接收到文件,并重新启动以等待新消息:

int readMsg(long fd, message_t *msg)
{
    if(msg == NULL || fd < 0) {errno = EINVAL; return -1;}

    int test;

    test = readHeader(fd, &(msg->hdr));
    if(test == -1 || test == 0){return -1;}

    test += readData(fd, &(msg->data));
    return test;
}

这是客户应该等待的地方,因为没有收入消息,在这种情况下,它会读取一些我不知道消息来源。

当我尝试使用GDB打印此不需要的消息时,它会打印:

{hdr = {op = 512, 
        sender = "\000\000\020G\032\324\t\000\000\n\000\000\000\000\030\021B\bC\n\000\000\v\000\000\000\000\021D\v\222\000"}, 
 data = {hdr = {receiver = "\000\000\000\000\021E\022C\n\000\000\b\v\000\000\000\000\021F\020I\n\000\000\020\000\006\b\002\n\000\000\006", 
         len = 131072}, 
 buf = 0x7ffff7f2f010 ""}`

当然,这是没有意义的。

我希望这个描述会有用

谢谢大家。

好的,我解决了我的问题。 如评论中所述,此问题是由于缺少对部分写作的检查所致

现在,函数readData()如下所示:

int readData(long fd, message_data_t *data)
{
    if(data == NULL || fd < 0) {errno = EINVAL; return -1;}

    int test;
    char* ph;
    unsigned int rd = 0;
    struct iovec iov;

    iov.iov_base = &(data->hdr);
    iov.iov_len = sizeof(message_data_hdr_t);

    test = readv(fd, &iov, 1);
    if(test <= 0){return -1;}

    if(data->hdr.len != 0)
    {
        data->buf = malloc(data->hdr.len);
        if(data->buf == NULL){return -1;}

        ph = data->buf;

        while (rd < data->hdr.len)
        {
            test = read(fd, ph, data->hdr.len - rd);
            if(test ==  -1)
                return -1;
            else if(test == 0)
            {
                errno = ENOENT;
                return -1;
            }

            rd += test;
            ph += test;
        }
    }

    return rd;
}

sendData()

int sendData(long fd, message_data_t *msg)
{
    if(msg == NULL || fd < 0) {errno = EINVAL; return -1;}

    int test;
    char* ph;
    unsigned int wr = 0;
    struct iovec iov;

    iov.iov_base = &(msg->hdr);
    iov.iov_len = sizeof(message_data_hdr_t);

    test = writev(fd, &(iov), 1);
    if(test == -1){return -1;}

    if(msg->hdr.len != 0)
    {
        ph = msg->buf;

        while (wr < msg->hdr.len)
        {
            test = write(fd, ph, msg->hdr.len - wr);
            if(test ==  -1)
                return -1;
            else if(test == 0)
            {
                errno = ENOENT;
                return -1;
            }

            wr += test;
            ph += test;
        }
    }

    return test;
}

这样,我不再发现错误。

谢谢您的帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM