Implement reliable file transfer with UDP

xiaoxiao2021-03-06  49

Using UDP to implement reliable file transmission, everyone is clear, if you use TCP to transfer files, it is very simple. It is very simple. If you don't worry, you will be lost, unless the network is broken, it will be returned. With UDP, because UDP is unreliable, use it to transfer files, to ensure that it is not packetified, we have to write extra code to protect it. This article says if reliable transmission is guaranteed. To achieve no error-free transmission data, we can use the Reissue Request (ARQ) protocol, which can also be divided into a continuous ARQ protocol, select the re-issue ARQ protocol, slide window protocol. This article focuses on the sliding window protocol, the other two interested reference related network communication, etc. The sliding window protocol is used to limit the number of data frames that have been sent but unrecognized. Repeat the serial number of those data frames received. The specific implementation is to set the sending window and the receiving window in the transmitting end and the receiving end, respectively. (1) Send window Send window is used to traffic control of the transmitting end. The size of the size of the send window wt represents the number of data frames that can be sent up to the maximum number of data frames that can be transmitted up to the other party's confirmation yet. Referring to the following figure: (2) The receiving window receiving window is used to control the received data frame. The data frame is allowed only if the transmit serial number of the received data frame falls within the received window, otherwise it will be discarded. The size of the receiving window is represented by WR, in the continuous ARQ protocol, WR = 1. The meaning of the receiving window can be referring to the following figure: There is such a relationship between the receiving window and the send window: After the receiving window is rotated, the send window may rotate forward, when the receiving window remains, the send window is not rotated. . This transceiver window is committed to the sliding window protocol in accordance with the protocol that constantly rotates in the direction of the clock-clock direction. Ok, after the sliding window protocol is generally understood, we will still enter the topic :) Sending thread: int Ret; DWORD DWRET; DWORD DWREAD; DWORD DWREADSIZE

Sendbuf * pushbuf;

SetEvent (m_hevent);

// If the size is transmitted to the file size and the front edge of the send window is equal to the rear edge, continue to send / / otherwise exit cyclic

If (m_dwsend

// If you send window size

Memset (Sendbuf.buf, 0, SIZEOF (Sendbuf.buf)); if (! Readfile (M_HFile, SENDBUF.BUF, DWREADSIZE, & DWREAD, NULL) {// AFXMessageBox ("Read file failed, please confirm that the file exists or There is a read permission. "); Cout <<" read file failed, confirm that the file exists or has read permissions. "<< endl; return false;}

m_dwsend = dwread;

Sendbuf.index = m_nsendindexhead; m_nsendindexhead = (m_nsendIndexhead 1)% sloding_window_size; // Send window frontier forward

Sendbuf.dwlen = dwread;

/ / Save the sent data to return: EntercriticalSection (& m_csqueue); // Enter m_bufqueue's exclusion area pushbuf = getBuffromLookaside ();

Memcpy (Pushbuf, & Sendbuf, Sizeof (Sendbuf));

m_bufqueue.push (pushbuf); if (m_dwsend> = m_dwfilesis) // The file is read, add a file_end flag in the queue to determine if you need to send {pushbuf = getBuffromLOOKASIDE ();

pushbuf-> index = File_End; pushbuf-> dwLen = File_End; memset (pushbuf-> buf, 0, sizeof (pushbuf-> buf)); m_bufqueue.push (pushbuf);} :: LeaveCriticalSection (& m_csQueue); // Exit M_Bufqueue's rejection area}

:: EntercriticalSECTION; // Enter m_bufqueue's rejection area if (m_bufqueue.front () -> index == file_end) // All packets have been sent, exit cyclic {: LeavecriticalSection (& m_csqueue); // Exit M_Bufqueue's exclusion zone Break;} else if (m_bufqueue.size () // The send window is less than the specified value, continue to send {RET = M_HSocket.hsendto ((char *) m_bufqueue.front (), sizeof (sendbuf) ); If (ret == socket_error) {: LeavecriticalSection; // Exit M_Bufqueue's rejection area Cout << "Send failed, re-issuing" << endl; continue;}

// Delay, prevent the packet loss SLEEP (50);} ELSE // The send window is greater than the specified value, wait for the receiving thread to receive confirmation message {resetEvent (m_hevent);} :: leavecriticalsection (& m_csqueue); // Exit M_BUFQUEUE exclusion District}} Receive thread: int RET; Recvbuf Recvbuf;

While (m_hfile! = null) {RET = m_hsocket.hrecvfrom ((char *) & recvbuf, sizeof (recvbuf)); if (RET == Socket_ERROR) {// AFXMessageBox ("Receive confirmation message error"); :: EntercriticalSECTION & m_csqueue); if (m_bufqueue.front () -> index == file_end) // file transfer {:: LeavecriticalSection (& m_csqueue); Break;} :: leavecriticalsection; & m_csqueue;

Cout << "Receive confirmation message error:" << getLastError () << endl; returnaf false;}

if (recvbuf.flag == Flag_Ack && recvbuf.index == m_nSendIndexTail) {m_nSendIndexTail = (m_nSendIndexTail 1)% Sliding_Window_Size; // the node has been confirmed, it is added lookaside list for reuse :: EnterCriticalSection (& m_csQueue); m_bufLookaside.push (m_bufqueue.front ()); m_bufqueue.pop (); :: LeaveCriticalSection (& m_csQueue); SetEvent (m_hEvent);}} thread receives the receiving end: int ret; DWORD dwWritten; sendBuf recvbuf; recvBuf Sendbuf; int Nerror = 0;

/ / Set the file pointer position, point to the size setFilePointer (M_HFILE, 0, NULL, FILE_END);

// If the file size has been received, continue while (m_dwsend

/ / Do not want to receive, discard, continue to receive IF (Recvbuf.index! = (M_nrecvindex)% sliding_window_size) {NERROR ; cout << recvbuf.index << "error?" << m_nrecvindex << endl; continue;}

IF (! Writefile (m_hfile, recvbuf.buf, recvbuf.dwlen, & dwritten, null) {// afxMessageBox ("write file failed"); cout << "write file failed" << Endl; return false;}

// Received file size m_dwsend = dwwritten;

// Send a confirmation message sendbuf.flag = flag_ack; sendbuf.index = m_nrecvindex; ret = m_hsocket.hsendto ((char *) & sendbuf, sizeof (sendbuf)); if (RET == Socket_ERROR) {Return False;

// Receive the window to move one m_nrecvindex = (m_nrecvindex 1)% sliding_window_size;} You can go to my home page to download the complete class, the class supports the breakpoint resumed, which is used to use auxiliary class Chsocket, also can download . Http://hackangel.go1.icpcn.com/lilisoft/udptrsmtfile.rar is used for server-side code as follows: CudPTRSMTFILE M_UDPTRSMTFILE;

m_udpTrsmtFile.SetRunType (true); m_udpTrsmtFile.SetFile ( "filename"); m_udpTrsmtFile.CreateSocket (TransmitFile_Port); m_udpTrsmtFile.SetSendSockAddr ( "192.168.10.30", TransmitFile_Port); m_udpTrsmtFile.BeginTransmitting (); for client code as follows: CUDPTrsmtFile m_udptrfile.setruntype (false); m_udptrsmtfile.setfile ("filename"); m_udptrsmtfile.createsSocket (TransmitFile_Port); m_udptrsmtfile.begintransmitting ();

转载请注明原文地址:https://www.9cbs.com/read-81680.html

New Post(0)