Problem mit send() und recv() in Chat-Programm [gelöst]
-
Kann diese Konstruktion gutgehen?
Auf Buttondruck soll hier eine Socketverbindung zu einem Server hergestellt werden. Steht also komplett so imWndProc(). Bloß machtWaitForSingleObject()nicht, was es soll. Die Threads beenden sich leider sofort wieder, wodurch die Verbindung sofort getrennt wird. Was kann ich tun?(Das Design mal bitte außer Acht lassen)
case 4: HANDLE threads[2]; unsigned long id; struct sockaddr_in addr; struct hostent *host; SOCKET s; WSADATA wsa; //if (argc != 3) //{ // // fprintf(stderr, "usage: %s <Host> <Port>\n", argv[0]); // return 1; //} if (WSAStartup(MAKEWORD(1, 1), &wsa)) { //fprintf(stderr, "WSAStartup() failed: %i\n", WSAGetLastError()); return 2; } if ((addr.sin_addr.s_addr = inet_addr("127.0.0.1")) == -1) { host = gethostbyname("127.0.0.1"); if (!host) { // fprintf(stderr, "gethostbyname() failed: %i\n", WSAGetLastError()); return 3; } addr.sin_addr = *(struct in_addr*)host->h_addr; } if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { // fprintf(stderr, "socket() failed: %i\n", WSAGetLastError()); return 4; } addr.sin_family = AF_INET; addr.sin_port = htons(atol("12345")); // printf("connecting to %s\n", inet_ntoa(addr.sin_addr)); if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) { // fprintf(stderr, "connect() failed: %i", WSAGetLastError()); return 5; } threads[0] = CreateThread(NULL, 0, reader, &s, 0, &id); threads[1] = CreateThread(NULL, 0, writer, &s, 0, &id); WaitForMultipleObjects(2, threads, FALSE, INFINITE); //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< closesocket(s); return 0; break; } return 0; case WM_DESTROY: PostQuitMessage (0); return 0; }
-
Ins Blaue getippt würde ich mal sagen, dass deine Threads sich automatisch wieder beenden - Zeig mal die Funktionen reader/writer
-
Ja genau, so war das auch, deswegen habe ich die Schleifen entfernt. Die beiden Threads sind nun unvollkommen. Hast du heiße Tipps, wie ich das lösen kann? Die Schleifen sollen den aufrufenden Prozess natürlich nicht blockieren.
DWORD WINAPI reader(PVOID pParam) { SOCKET s; s = *(SOCKET*)pParam; while(buf) { cut(buf); strcat(buf, "\r\n"); send(s, buf, strlen(buf), 0); } // MessageBox(NULL,itoa(GetLastError(),bufg,10),"",0); return 0; } char buffer[BUF_SIZ]; DWORD WINAPI writer(PVOID pParam) { SOCKET s; s = *(SOCKET*)pParam; recv(s, buffer, sizeof(buffer), 0); return 0; }
-
du wirst mit select(), also mit nicht blockierenden senden/empfangen arbeiten müssen.
Hier mal ne super seite, wo senden/empfangen und auch select() super erklärt sind.
-
Ich komme leider nicht klar damit. Muss ich
WaitForSingleObject()benutzen, um auf die Eingabe des Clients zu reagieren? Also, wenn Senden gedrückt wird, soll natürlich send() ausgeführt werden. Wie soll man das schreiben? Die Schleife soll dabei natürlich WARTEN, bis der Button gedrückt wurde.recv()wartet dankselect()ja schon...Empfang funktioniert schon.
Das ist übrigens mein Client. Der Server funktioniert ohne Probleme.
//----------------------------------------------------------------------------------- char buf[BUF_SIZ], buffer[BUF_SIZ]; LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static HWND hwndButton1, hwndButton2, hwndEdit2, hwndEdit3; bool SCHICKEN = false; switch (message) { case WM_PAINT: hdc = BeginPaint (hwnd, &ps); EndPaint (hwnd, &ps); return 0; case WM_CREATE : hwndButton1 = CreateWindow ( "button", "Senden", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 230, 230, 100, 40, hwnd, (HMENU)1, (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL); hwndButton2 = CreateWindow ( "button", "Verbinden", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 230, 100, 100, 40, hwnd, (HMENU)4, (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL); hwndEdit2 = CreateWindow ( "edit", "", WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | WS_BORDER | ES_AUTOVSCROLL, 20, 230, 200, 40, hwnd, (HMENU)2, (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL); hwndEdit3 = CreateWindow ( "edit", "", WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | WS_BORDER | ES_AUTOVSCROLL, 20, 20, 200, 200, hwnd, (HMENU)3, (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL); return 0; case WM_COMMAND: switch(LOWORD(wParam)) { case 1: GetWindowText(hwndEdit2,buffer,BUF_SIZ); strcat(buffer, "\r\n\r\n"); SetWindowText(hwndEdit2,""); SCHICKEN = true; break; case 2: break; case 3: break; case 4: struct sockaddr_in addr; struct hostent *host; SOCKET s; WSADATA wsa; fd_set fdSetRead; TIMEVAL timeout; int rc; if (WSAStartup(MAKEWORD(1, 1), &wsa)) { //fprintf(stderr, "WSAStartup() failed: %i\n", WSAGetLastError()); return 2; } if ((addr.sin_addr.s_addr = inet_addr("127.0.0.1")) == -1) { host = gethostbyname("127.0.0.1"); if (!host) { // fprintf(stderr, "gethostbyname() failed: %i\n", WSAGetLastError()); return 3; } addr.sin_addr = *(struct in_addr*)host->h_addr; } if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { // fprintf(stderr, "socket() failed: %i\n", WSAGetLastError()); return 4; } addr.sin_family = AF_INET; addr.sin_port = htons(atol("12345")); // printf("connecting to %s\n", inet_ntoa(addr.sin_addr)); if (rc = connect(s, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) { // fprintf(stderr, "connect() failed: %i", WSAGetLastError()); return 5; } while(rc!=SOCKET_ERROR) { //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< blockiert! if(SCHICKEN == true) { send(s,buffer,strlen(buffer),0); SCHICKEN = false; } FD_ZERO(&fdSetRead); FD_SET(s,&fdSetRead); timeout.tv_sec=0; timeout.tv_usec=0; while((rc=select(0,&fdSetRead,NULL,NULL,&timeout))>0) { rc=recv(s,buf,1023,0); if(rc==0) { // printf("Server closed connection!\n"); return 1; } else if(rc==SOCKET_ERROR) { // printf("Error: recv failed: %d\n",WSAGetLastError()); return 1; } // empfangene daten ausgeben // print received data buf[rc]='\0'; Edit_ReplaceSel(hwndEdit3,buf); // printf("%s\n",buf); } } closesocket(s); return 0; break; } return 0; case WM_DESTROY: PostQuitMessage (0); return 0; } return DefWindowProc (hwnd, message, wParam, lParam); }
-
WaitForSingleObject() wartet, bis
a) Die Zeit abgelaufen ist
oder b) Der Thread beendet wurde.Du müsstest nur die Threads starten, und diesen dann (z.B. mit einer globalen Variable) mitteilen, wann sie etwas senden/ empfangen sollen.
Du musst dir einen Thread etwa wie ein weiteres Programm vorstellen, welches mit der angegebenen Funktionn anfängt zu laufen, bis es das Ende dieser Funktion erreicht hat. Also musst du innerhalb von reader/writer einen kompletten Code schreiben, der auf die ganzen Ereignisse (Button gedrückt, ende, etc. eingeht)
-
Und du musst die Threads synchronisieren! Ansonsten zerreißt es dein Programm früher oder später.
-
Ich habe das Konzept mit den Threads verworfen. Siehe meinen vorletzten Post. In Zeile 92 ist mein Problem.
-
Hat sich erledigt. Habe einfach einen Thread dafür benutzt.