繁体   English   中英

如何通过套接字发送所有数据?

[英]How can I send all data over a socket?

我试图通过套接字发送大量数据,有时当我调用send(在Windows上)时,它不会按预期发送所有我请求的数据。 因此,我编写了一个应该可以解决我的问题的小函数-但这会导致无法正确发送数据并导致图像损坏的问题。 我正在建立一个简单的聊天室,您可以在其中互相发送图像(屏幕截图)。

为什么我的功能不起作用?

我该如何运作?

void _internal_SendFile_alignment_512(SOCKET sock, BYTE *data, DWORD datasize)
{       
    Sock::Packet packet;
    packet.DataSize = datasize;
    packet.PacketType = PACKET_FILETRANSFER_INITIATE;
    DWORD until = datasize / 512;

    send(sock, (const char*)&packet, sizeof(packet), 0);

    unsigned int pos = 0;

    while( pos != datasize )
    {
        pos += send(sock, (char *)(data + pos), datasize - pos, 0);
    }

}

我的接收方是:

public override void OnReceiveData(TcpLib.ConnectionState state)
{
    if (state.fileTransfer == true && state.waitingFor > 0)
    {
        byte[] buffer = new byte[state.AvailableData];
        int readBytes = state.Read(buffer, 0, state.AvailableData);
        state.waitingFor -= readBytes;
        state.bw.Write(buffer);
        state.bw.Flush();

        if (state.waitingFor == 0)
        {
            state.bw.Close();
            state.hFile.Close();
            state.fileTransfer = false;
            IPEndPoint ip = state.RemoteEndPoint as IPEndPoint;
            Program.MainForm.log("Ended file transfer with " + ip);
        }
    }
    else if( state.AvailableData > 7)
    {          
        byte[] buffer = new byte[8];
        int readBytes = state.Read(buffer, 0, 8);
        if (readBytes == 8)
        {
            Packet packet = ByteArrayToStructure<Packet>(buffer);
            if (packet.PacketType == PACKET_FILETRANSFER_INITIATE)
            {
                IPEndPoint ip = state.RemoteEndPoint as IPEndPoint;
                String filename = getUniqueFileName("" + ip.Address);
                if (filename == null)
                {
                    Program.MainForm.log("Error getting filename for " + ip);

                    state.EndConnection();
                    return;
                }

                byte[] data = new byte[state.AvailableData];
                readBytes = state.Read(data, 0, state.AvailableData);

                state.waitingFor = packet.DataSize - readBytes;
                state.hFile = new FileStream(filename, FileMode.Append);
                state.bw = new BinaryWriter(state.hFile);
                state.bw.Write(data);
                state.bw.Flush();
                state.fileTransfer = true;
                Program.MainForm.log("Initiated file transfer with " + ip);
            }
        }
    }
}

当我调试代码并看到send()不会返回总数据大小(即必须多次调用)并且图像中出现黄线或紫线时,它会接收所有数据,并且我怀疑其中有发送数据时出现问题。

我误解了问题和解决方案的意图。 感谢@Remy Lebeau的评论以澄清这一点。 基于此,您可以编写http://beej.us/guide/bgnet/output/print/bgnet_USLetter.pdf 7.3节中给出的sendall()函数。

int sendall(int s, char *buf, int *len)
{
    int total = 0; // how many bytes we've sent
    int bytesleft = *len; // how many we have left to send
    int n = 0;
    while(total < *len) {
       n = send(s, buf+total, bytesleft, 0);
       if (n == -1) { 
           /* print/log error details */
           break;
       }
       total += n;
       bytesleft -= n;
    }
    *len = total; // return number actually sent here
    return n==-1?-1:0; // return -1 on failure, 0 on success
}

您需要检查send()的返回值。 特别是,您不能简单地假设它是发送的字节数,还可能会出现错误。 尝试以下方法:

while(datasize != 0)
{
    n = send(...);
    if(n == SOCKET_ERROR)
        throw exception("send() failed with errorcode #" + to_string(WSAGetLastEror()));
    // adjust pointer and remaining number of bytes
    datasize -= n;
    data += n;
}

顺便说一句:

  • 使BYTE const* data您不会修改它指向的内容。
  • 您的其余代码似乎太复杂了,特别是您无法通过对齐512之类的幻数来解决问题。

暂无
暂无

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

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