Witam, piszę prosty program, który wysyła plik tekstowy przez sieć do już gotowego serwera. Używam asynchronicznych socketów opartych na komunikatach. Na msdn przeczytałem, że w przypadku braku miejsca w buforze po stronie serwera funkcja send zwraca kod błędu WSAEWOULDBLOCK, a dalsze wysyłanie będzie możliwe po wystąpieniu FD_WRITE. Początkowo wysyłałem małe pliki i wszystko było ok. Dane były całkowicie wysłane jednym send. Napisałem obsługę FD_WRITE i zacząłem wysyłać większe pliki . Zauważyłem, że FD_WRITE nie występuje. Wszystko wysyła się w jednym send, a aplikacja zdaje się blokować (problemy z przesuwaniem okna podczas wysyłania). FD_WRITE nie występuje nawet kiedy wysyłam plik 45MB a send nie zwraca WSAEWOULDBLOCK. Co robię źle? Zamieszczam kod:
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <fstream>
#include <string>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#define SOCKET_EVENT WM_USER + 1
#define OK_BUTTON 201
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
SOCKET hSocket;
char *buff = NULL;
unsigned bytes_sent = 0;
unsigned buff_size = 0;
int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
WNDCLASSEX wndclassex;
HWND hMainWindow;
MSG messages;
wndclassex.hInstance = hThisInstance;
wndclassex.cbSize = sizeof(WNDCLASSEX);
wndclassex.cbWndExtra = 0;
wndclassex.cbClsExtra = 0;
wndclassex.lpfnWndProc = WndProc;
wndclassex.lpszMenuName = 0;
wndclassex.lpszClassName = "MainWindow";
wndclassex.style = 0;
wndclassex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclassex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wndclassex.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclassex.hbrBackground = (HBRUSH)COLOR_WINDOW;
if(!RegisterClassEx(&wndclassex)) return -1;
hMainWindow = CreateWindowEx(0, "MainWindow", "Klient", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 200, 100, HWND_DESKTOP, 0, hThisInstance, 0);
if(hMainWindow == NULL) return -1;
ShowWindow(hMainWindow, nShowCmd);
UpdateWindow(hMainWindow);
while(true) {
if(PeekMessage(&messages, 0, 0, 0, PM_REMOVE)) {
if(messages.message == WM_QUIT) break;
TranslateMessage(&messages);
DispatchMessage(&messages);
}
else WaitMessage();
}
return messages.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch(uMsg) {
case WM_CREATE: {
WSADATA wsadata;
if(WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) break;
hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(hSocket == INVALID_SOCKET) {
WSACleanup();
break;
}
WSAAsyncSelect(hSocket, hWnd, SOCKET_EVENT, FD_WRITE | FD_READ | FD_CONNECT | FD_CLOSE);
sockaddr_in sockAddr;
sockAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.14");
sockAddr.sin_port = htons(1234);
sockAddr.sin_family = AF_INET;
connect(hSocket, (sockaddr*)&sockAddr, sizeof(sockAddr));
HWND hOkButton = CreateWindowEx(0, "BUTTON", "OK", WS_CHILD | WS_VISIBLE, 5, 5, 60, 23, hWnd, (HMENU)OK_BUTTON, GetModuleHandle(0), 0);
HFONT hDefaultFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
SendMessage(hOkButton, WM_SETFONT, (WPARAM)hDefaultFont, 0);
} break;
case SOCKET_EVENT: {
if(WSAGETSELECTERROR(lParam)) break;
switch(WSAGETSELECTEVENT(lParam)) {
case FD_CONNECT:
MessageBox(hWnd, "Connected to the server.", "info", 0);
break;
case FD_READ:
MessageBox(hWnd, "FD_READ", "info", 0);
break;
case FD_WRITE:
ofstream trace_file("trace.txt", ios::app);
static int counter = 0;
trace_file << "fd_write: " << ++counter << endl;
if(buff == NULL) break;
if(buff_size == bytes_sent) {
delete []buff;
buff = NULL;
buff_size = 0;
bytes_sent = 0;
break;
}
char *temp_buff = new char[sizeof(buff) - bytes_sent];
strcpy_s(temp_buff, sizeof(buff) - bytes_sent, buff);
bytes_sent += send(hSocket, temp_buff, sizeof(temp_buff), 0);
break;
}
} break;
case WM_COMMAND: {
switch(LOWORD(wParam)) {
case OK_BUTTON: {
ifstream file("plik.txt");
string line;
string strFile;
while(getline(file, line)) {
strFile += line + '\n';
}
buff = new char[strFile.length()];
buff_size = strFile.length();
strcpy(buff, strFile.c_str());
bytes_sent = send(hSocket, buff, strlen(buff), 0);
if(bytes_sent == SOCKET_ERROR) {
if(WSAGetLastError() == WSAEWOULDBLOCK) {
MessageBox(hWnd, "WSAEWOULDBLOCK", "info", MB_ICONINFORMATION);
}
}
} break;
}
} break;
case WM_DESTROY:
closesocket(hSocket);
PostQuitMessage(0);
break;
default: return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}