下面是数据传输的重点-CDataSocket类,函数不多,都比较重要。
1、OnAccept 数据tcp服务器被连接的虚函数,由框架调用。
1 void CDataSocket::OnAccept(intnErrorCode)2 {3 //Accept the connection using a temp CSocket object.
4 CAsyncSocket tmpSocket;5 Accept(tmpSocket);6
7 SOCKET socket =tmpSocket.Detach();8 Close();9
10 Attach(socket);11
12 m_bConnected =TRUE;13
14 CAsyncSocket::OnAccept(nErrorCode);15 }
第7行 得到套接字描述符socket。第8行关闭监听的这个套接字,第11行关联socket与本对象,第12行,标记连接标志。这种处理方法少写一个类。因为tcp监听得一个socket,而连接上来的客户端也需要一个socket来与之通信。这样做适合只有一个客户端的情况。
2、OnReceive 数据接收处理函数
1 intCDataSocket::Receive()2 {3 TRACE("OnReceive\n");4 int nRead = 0;5
6 if (m_pControlSocket->m_nStatus ==STATUS_UPLOAD)7 {8 if (m_File.m_hFile ==NULL)9 return 0;10
11 bytedata[PACKET_SIZE];12 nRead =CAsyncSocket::Receive(data, PACKET_SIZE);13
14 switch(nRead)15 {16 case 0:17 {18 m_File.Close();19 m_File.m_hFile =NULL;20 Close();21 //tell the client the transfer is complete.
22 m_pControlSocket->SendResponse("226 Transfer complete");23 //destroy this socket
24 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);25 break;26 }27 caseSOCKET_ERROR:28 {29 if (GetLastError() !=WSAEWOULDBLOCK)30 {31 m_File.Close();32 m_File.m_hFile =NULL;33 Close();34 m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");35 //destroy this socket
36 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);37 }38 break;39 }40 default:41 {42 TRY43 {44 m_File.Write(data, nRead);45 }46 CATCH_ALL(e)47 {48 m_File.Close();49 m_File.m_hFile =NULL;50 Close();51 m_pControlSocket->SendResponse("450 Can‘t access file.");52 //destroy this socket
53 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);54 return 0;55 }56 END_CATCH_ALL;57 break;58 }59 }60 }61 returnnRead;62 }
如果处于上传状态,那么将接收到的数据写入文件。
3、PreSendFile 与发送文件有关的函数
1 BOOL CDataSocket::PrepareSendFile(LPCTSTR lpszFilename)2 {3 //close file if it‘s already open
4 if (m_File.m_hFile !=NULL)5 {6 m_File.Close();7 }8
9 //open source file
10 if (!m_File.Open(lpszFilename, CFile::modeRead |CFile::typeBinary))11 {12 returnFALSE;13 }14 m_nTotalBytesSend =m_File.GetLength();15
16 if (m_pControlSocket->m_dwRestartOffset m_dwRestartOffset;19 }20 else
21 {22 m_nTotalBytesTransfered = 0;23 }24 returnTRUE;25 }
初始化文件描述符m_File,m_nTotalBytesSend,m_nTotalBytesTransfered。
4、 SendFile函数 调用PrepareSendFile,调用OnSend发送文件。
1 voidCDataSocket::SendFile(LPCTSTR lpszFilename)2 {3 if (!PrepareSendFile(lpszFilename))4 {5 //change status
6 m_pControlSocket->m_nStatus =STATUS_IDLE;7
8 m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");9
10 //destroy this socket
11 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);12 return;13 }14 OnSend(0);15 }
5、SendData 发送数据 是为了LIST命令而准备,发送文件目录列表。
6、OnSend 主要区分了list命令的情况和download的情况。
1 void CDataSocket::OnSend(intnErrorCode)2 {3 CAsyncSocket::OnSend(nErrorCode);4 switch(m_pControlSocket->m_nStatus)5 {6 caseSTATUS_LIST:7 {8 while (m_nTotalBytesTransfered
13 CString strDataBlock;14
15 dwRead =m_strData.GetLength();16
17 if (dwRead <=PACKET_SIZE)18 {19 strDataBlock =m_strData;20 }21 else
22 {23 strDataBlock =m_strData.Left(PACKET_SIZE);24 dwRead =strDataBlock.GetLength();25 }26
27 if ((dwBytes = Send(strDataBlock, dwRead)) ==SOCKET_ERROR)28 {29 if (GetLastError() ==WSAEWOULDBLOCK)30 {31 Sleep(0);32 return;33 }34 else
35 {36 TCHAR szError[256];37 wsprintf(szError, "Server Socket failed to send: %d", GetLastError());38
39 //close the data connection.
40 Close();41
42 m_nTotalBytesSend = 0;43 m_nTotalBytesTransfered = 0;44
45 //change status
46 m_pControlSocket->m_nStatus =STATUS_IDLE;47
48 m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");49
50 //destroy this socket
51 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);52 }53 }54 else
55 {56 m_nTotalBytesTransfered +=dwBytes;57 m_strData =m_strData.Mid(dwBytes);58 }59 }60 if (m_nTotalBytesTransfered ==m_nTotalBytesSend)61 {62 //close the data connection.
63 Close();64
65 m_nTotalBytesSend = 0;66 m_nTotalBytesTransfered = 0;67
68 //change status
69 m_pControlSocket->m_nStatus =STATUS_IDLE;70
71 //tell the client the transfer is complete.
72 m_pControlSocket->SendResponse("226 Transfer complete");73 //destroy this socket
74 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);75 }76 break;77 }78 caseSTATUS_DOWNLOAD:79 {80 while (m_nTotalBytesTransfered
83 bytedata[PACKET_SIZE];84
85 m_File.Seek(m_nTotalBytesTransfered, CFile::begin);86
87 DWORD dwRead =m_File.Read(data, PACKET_SIZE);88
89 intdwBytes;90
91 if ((dwBytes = Send(data, dwRead)) ==SOCKET_ERROR)92 {93 if (GetLastError() ==WSAEWOULDBLOCK)94 {95 Sleep(0);96 break;97 }98 else
99 {100 TCHAR szError[256];101 wsprintf(szError, "Server Socket failed to send: %d", GetLastError());102
103 //close file.
104 m_File.Close();105 m_File.m_hFile =NULL;106
107 //close the data connection.
108 Close();109
110 m_nTotalBytesSend = 0;111 m_nTotalBytesTransfered = 0;112
113 //change status
114 m_pControlSocket->m_nStatus =STATUS_IDLE;115
116 m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");117
118 //destroy this socket
119 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);120 }121 }122 else
123 {124 m_nTotalBytesTransfered +=dwBytes;125 }126 }127 if (m_nTotalBytesTransfered ==m_nTotalBytesSend)128 {129 //close file.
130 m_File.Close();131 m_File.m_hFile =NULL;132
133 //close the data connection.
134 Close();135
136 m_nTotalBytesSend = 0;137 m_nTotalBytesTransfered = 0;138
139 //change status
140 m_pControlSocket->m_nStatus =STATUS_IDLE;141
142 //tell the client the transfer is complete.
143 m_pControlSocket->SendResponse("226 Transfer complete");144 //destroy this socket
145 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);146 }147 break;148 }149 }150 }
7、OnConnect函数 tcp连接成功时被框架调用的虚函数。
8、OnClose函数 当数据发送完成或者接收完成后被框架调用的虚函数。主要做清理工作。
9、