我目前有一個客戶端應用程序,但它是單線程的。如何處理多線程服務器客戶端程序中的數據包?
我的數據包是這樣的:< len_of_data> | <數據>」
「|」 被用作我的數據的分離
< len_of_data>總是長跟着4位
<數據>的樣子:|。<事務ID> | <命令> | < buflen> | < BUF> | <校驗> |
我的代碼來創建數據包是:
_snprintf_s(data_buffer, WS_MAX_DATA_PACKET_SIZE,
WS_MAX_DATA_PACKET_SIZE - 1,
"%s%d%s%d%s%d%s%s%s%d%s",
WS_PACKET_SEP, pkt->transaction_id,
WS_PACKET_SEP, pkt->command,
WS_PACKET_SEP, pkt->bufsize,
WS_PACKET_SEP, pkt->buf,
WS_PACKET_SEP, pkt->checksum, WS_PACKET_SEP);
buf_len = strlen(data_buffer);
_snprintf_s(send_buffer, WS_MAX_DATA_PACKET_SIZE,
WS_MAX_DATA_PACKET_SIZE - 1, "%04d%s%s",
buf_len, WS_PACKET_SEP, data_buffer);
buf_len = strlen(send_buffer);
// Send buffer
bytes_sent = send(ConnectSocket, send_buffer, buf_len, 0);
客戶端線程向服務器發送命令,然後調用GetIncomingPackets()函數。在GetIncomingPackets()中,我調用recv()來獲得5個字節,這應該是其餘數據包的len,我解析這5個字節並驗證它們是否符合我的預期格式。然後我將前4個字節轉換爲一個整數x。然後我再次調用recv()來獲得更多的x字節,然後將它們解析到我的數據包結構中。
當我添加另一個線程來做同樣的事情(發送和接收命令)時,會發生問題。 我開始我的應用程序並激發2個線程併發送它們發送不同的命令並等待響應。當線程調用GetIncomingPackets()時,我回來的數據是無效的。我期望的前5個字節有時會丟失,而我只會得到以下5個字節,因此我無法獲取我的len_of_data>數據包。
我甚至在我的GetIncomingPackets()中的2個recv()調用之間添加了一個臨界區塊,以便在獲取完整數據包時不會相互中斷。 沒有錯誤檢查一些額外的代碼,此功能如何看起來像
#define WS_SIZE_OF_LEN_PACKET 5
bool GetIncomingPackets(SOCKET sd, dev_sim_packet_t *pkt)
{
char len_str_buf[WS_SIZE_OF_LEN_PACKET + 1] = {0}; // + 1 for NULL char
char data_buf[WS_MAX_DATA_PACKET_SIZE + 1] = {0};
int ret = 0;
int data_len = 0;
EnterCriticalSection(&recv_critical_section);
nReadBytes = WS_RecvAll(sd, len_str_buf, WS_SIZE_OF_LEN_PACKET);
ret = WS_VerifyLenPacket(len_str_buf);
// Convert data packet lenght string received to int
data_len = WS_ConvertNumberFromString(len_str_buf, WS_SIZE_OF_LEN_PACKET);
// Get data from packet
nReadBytes = WS_RecvAll(sd, data_buf, data_len);
LeaveCriticalSection(&recv_critical_section );
ret = ParseMessager(data_buf, data_len, pkt);
}
我的問題是,這可能是造成這個問題,我怎麼能解決這個問題?或者有更好的方法來做我想做的事情。我試圖讓它成爲多線程的原因是因爲我的應用程序將與其他兩個源進行通信,並且我想要一個線程來處理來自任一來源的每個請求。
在此先感謝您,如果我沒有解釋清楚,請隨時提出任何問題。
下面是WS_RecvAll()的代碼。該緩衝區),這樣在GetIncomingPackets(聲明靜態緩衝區:
char data_buf[WS_MAX_DATA_PACKET_SIZE + 1] = {0}; // + 1 for NULL char
int WS_RecvAll(SOCKET socket_handle, char* buffer, int size)
{
int ret = 0;
int read = 0;
int i = 0;
char err_buf[100] = {0};
while(size)
{
ret = recv(socket_handle, &buffer[read], size, 0);
if (ret == SOCKET_ERROR)
{
printf("***ERROR***: recv failed, error = %d\n", WSAGetLastError());
return WS_ERROR_RECV_FAILED;
}
if (ret == 0) {
break;
}
read += ret;
size -= ret;
}
return read;
}
客戶端和服務器之間的協議是什麼? (即TCP還是UDP?) – Nick 2011-05-09 15:35:59
它是TCP ...... – emge 2011-05-09 15:46:45
發佈WS_RecvAll的代碼。 – 2011-05-09 15:49:08