[英]C++ win32 async socket client send() issue
我必須編寫一個WIN32,異步套接字客戶端應用程序,它連接到服務器。 我可以啟動程序,連接到服務器,接收並繼續接收數據,但是當我嘗試向服務器發送消息時,服務器上沒有任何反應。 我沒有任何套接字錯誤消息,send()函數返回正確的發送字節。 但服務器看起來好像沒有收到任何東西。 我的send()在FD_READ語句中調用,首先是if語句。 我試圖將其移動到其他語句(WM_CREATE,FD_WRITE,FD_CONNECT),但仍然是同一個問題。 我試圖找出什么是錯的,從一個mounth看很多論壇,但我沒有發現問題。 任何幫助將非常感激。 這是我的代碼示例(我跳過了非常有趣的部分):
#include <windows.h>
#include <fstream>
#include <sstream>
#include<process.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
#define IDC_BUTTON_CONNECT 101 // Button identifiers
#define IDC_EDIT_IP 102 // Edit / Text box identifiers
#define IDC_EDIT_PORT 103
#define IDC_EDIT_DEBUG 104
#define WM_SOCKET 105 // Socket messages structure identifier
HWND hWnd;
HWND hEditIp;
HWND hEditPort;
HWND hDebug;
HWND hButtonConnect;
HANDLE hReadMutex;
SOCKET Socket = NULL;
SOCKADDR_IN SockAddr;
char *ip = "";
char *port = "";
bool connectStatus = FALSE;
char readBuffer[5000];
char id[32];
char version[256];
LPSTR statusText = TEXT("Connecting...");
LRESULT CALLBACK WinProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
// WinMain...
// appendTextToEdit function...
// incoming data processing thread (not used yet)...
LRESULT CALLBACK WinProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
// Get IP and port from file "config.ini"...
//Create windows for IP, Port and Debug...
// Create "connect" button...
WSADATA WsaDat; // Winsock initialization...
int nResult=WSAStartup(MAKEWORD(2,2),&WsaDat);
if(nResult!=0)
{
statusText=TEXT("Winsock initialization failed");
InvalidateRect(hWnd, NULL, TRUE);
break;
}
Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); // Creating socket...
if(Socket==INVALID_SOCKET)
{
statusText=TEXT("Socket creation failed");
InvalidateRect(hWnd, NULL, TRUE);
break;
}
nResult=WSAAsyncSelect(Socket,hWnd,WM_SOCKET,(FD_CLOSE|FD_READ|FD_WRITE|FD_CONNECT)); // Select AsyncSocket events...
if(nResult)
{
statusText=TEXT("WSAAsyncSelect failed");
InvalidateRect(hWnd, NULL, TRUE);
break;
}
// Set up our socket address structure...
SockAddr.sin_addr.s_addr=inet_addr(ip);
SockAddr.sin_port=htons(atoi(port));
SockAddr.sin_family=AF_INET;
connect(Socket,(LPSOCKADDR)(&SockAddr),sizeof(SockAddr)); // Connexion command
}
break;
case WM_PAINT:
{
// painting / updating the window...
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_BUTTON_CONNECT:
{
if(connectStatus==FALSE) // Avoid to reconnect when already online...
{
// Window repaint with updated text (statusText = global variable)
statusText=TEXT("Connecting...");
InvalidateRect(hWnd, NULL, TRUE);
// Retrieve edit box datas and store to variables and file...
// Saving data to "config.ini" file...
// Reinitializing adress structure with new host adress and port from edit boxes, and reconnect attempt...
SockAddr.sin_addr.s_addr=inet_addr(ip);
SockAddr.sin_port=htons(atoi(port));
SockAddr.sin_family=AF_INET;
connect(Socket,(LPSOCKADDR)(&SockAddr),sizeof(SockAddr));
}
break;
}
break;
}
break;
case WM_SOCKET:
{
switch(WSAGETSELECTEVENT(lParam))
{
case FD_CONNECT:
{
connectStatus = TRUE;
statusText=TEXT("Connected");
}
case FD_READ:
{
appendTextToEdit(hDebug, "FD_READ event...\n");
char *rawVariable = nullptr;
char *next_token = nullptr;
recv(Socket, readBuffer, sizeof(readBuffer), 0);
rawVariable = readBuffer;
if(strstr(rawVariable, "id=") != NULL) // Identifying message sent by the server (starts with id, version, ...) and store the values to variables (working fine)
{
char *label = strtok_s(rawVariable, "=", &next_token);
char *pId = strtok_s(NULL, "\n", &next_token);
rawVariable = strtok_s(NULL, "", &next_token);
strcpy_s(id, pId);
char message[256] = "Qh57=1"; // Setting up message structure... (the server should do an action when it receives "Qh57=1\r\n" but it doesn't...) here is my problem...
appendTextToEdit(hDebug, "Message sent : ");
appendTextToEdit(hDebug, message);
char *endline = "\r\n";
strcat_s(message, endline);
string messageString(message);
int messageLength = ((messageString.length()) - 2); // Get outgoing string length (-2)
int sent = send(Socket, message , messageLength , 0);
char buffer [33]; // Display number of bytes sent...
_itoa_s(sent,buffer,10);
appendTextToEdit(hDebug, " (");
appendTextToEdit(hDebug, buffer);
appendTextToEdit(hDebug, " bytes sent)\n");
}
if( strstr(rawVariable, "version") != NULL)
{
char *label = strtok_s(rawVariable, "=", &next_token);
char *pVersion = strtok_s(NULL, "\n", &next_token);
rawVariable = strtok_s(NULL, "", &next_token);
strcpy_s(version, pVersion);
}
appendTextToEdit(hDebug, "End of FD_READ\n");
}
break;
case FD_WRITE:
{
appendTextToEdit(hDebug, "FD_WRITE event...\n");
appendTextToEdit(hDebug, "End of FD_WRITE\n");
}
break;
case FD_CLOSE:
{
statusText = "Disconnected from server";
connectStatus = FALSE;
InvalidateRect(hWnd, NULL, TRUE);
// SendMessage(hWnd, WM_DESTROY, NULL, NULL); // Final version...
}
break;
}
break;
}
break;
case WM_DESTROY:
{
closesocket(Socket);
WSACleanup();
PostQuitMessage(0);
return 0;
}
break;
}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
問題是您正在向服務器發送不完整的消息,因此它不會執行任何操作。 根據您自己在代碼中的注釋:
the server should do an action when it receives "Qh57=1\r\n" but it doesn't...
它永遠不會收到\\r\\n
,因為你永遠不會發送它:
char message[256] = "Qh57=1";
...
char *endline = "\r\n";
strcat_s(message, endline); // <-- you do append a CRLF...
string messageString(message);
int messageLength = ((messageString.length()) - 2); // <-- but you subtract the CRLF from the message length...
int sent = send(Socket, message , messageLength , 0); // <-- so the CRLF is not sent!
不要從消息長度中減去CRLF:
int messageLength = messageString.length();
順便說一下,使用std:string
來計算消息長度是浪費內存。 您可以使用strlen()
代替:
int messageLength = strlen(message);
流套接字連接對消息邊界一無所知。 它只傳輸字節,就像RS232連接一樣。 如果你仔細閱讀recv
的文檔,你會發現一個成功的recv
調用可以在一個字節和指定的緩沖區大小之間的任何地方“返回”(=復制到緩沖區) - 這取決於已經接收了多少數據。 recv
s返回值將告訴您已復制了多少。 如果跟隨更多數據,則將通過后續的recv
調用返回。 這意味着如果服務器發送id=3\\nversion=10.0.5\\nQh57=0\\nQs323=-999999\\n
您的第一次recv
調用可能會返回id=3\\nversion=10.0.5\\nQh
,第二次可能會返回57=0\\nQs323=-999999\\n
。 或者你可以用3個塊來獲得它。 或者4.或者甚至一次一個字節。
解決這個問題的最簡單的方法,不幸的是性能非常差,是重復調用recv
,緩沖區大小為一個字節。 直到你看到你收到了整條信息(在你的例子中,這將是在收到4 \\n
字符之后)。
首選的方式是:
recv
recv
返回到“消息組裝緩沖區”
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.