简体   繁体   English

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

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

I am trying to send large amounts of data over a socket, sometimes when I call send (on Windows) it won't send all the data I requested, as expected. 我试图通过套接字发送大量数据,有时当我调用send(在Windows上)时,它不会按预期发送所有我请求的数据。 So, I wrote a little function that should have solved my problems- but it's causing problems where the data isn't being sent correctly and causing the images to be corrupted. 因此,我编写了一个应该可以解决我的问题的小函数-但这会导致无法正确发送数据并导致图像损坏的问题。 I'm making a simple chat room where you can send images (screenshots) to each other. 我正在建立一个简单的聊天室,您可以在其中互相发送图像(屏幕截图)。

Why is my function not working? 为什么我的功能不起作用?

How can I make it work? 我该如何运作?

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);
    }

}

My receive side is: 我的接收方是:

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);
            }
        }
    }
}

It receives all the data, when I debug my code and see that send() does not return the total data size (ie it has to be called more than once) and the image gets yellow lines or purple lines in it — I suspect there's something wrong with sending the data. 当我调试代码并看到send()不会返回总数据大小(即必须多次调用)并且图像中出现黄线或紫线时,它会接收所有数据,并且我怀疑其中有发送数据时出现问题。

I mis-understood the question and solution intent. 我误解了问题和解决方案的意图。 Thanks @Remy Lebeau for the comment to clarify that. 感谢@Remy Lebeau的评论以澄清这一点。 Based on that, you can write a sendall() function as given in section 7.3 of http://beej.us/guide/bgnet/output/print/bgnet_USLetter.pdf 基于此,您可以编写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
}

You need to check the returnvalue of send(). 您需要检查send()的返回值。 In particular, you can't simply assume that it is the number of bytes sent, there is also the case that there was an error. 特别是,您不能简单地假设它是发送的字节数,还可能会出现错误。 Try this instead: 尝试以下方法:

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;
}

BTW: 顺便说一句:

  • Make that BYTE const* data , you're not going to modify what it points to. 使BYTE const* data您不会修改它指向的内容。
  • The rest of your code seems too complicated, in particular you don't solve things by aligning to magic numbers like 512. 您的其余代码似乎太复杂了,特别是您无法通过对齐512之类的幻数来解决问题。

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

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