[C++] Filetransfer via tcp protocol



  • hustbaer schrieb:

    BTW: wenn du volle Geschwindigkeit haben willst solltest du mehr als 8K Puffer verwenden. Wenn das Programm sehr viele Verbindungen gleichzeitig (min. >100) ist Speicher sparen eine sehr gute Idee. Sonst würde ich sagen zwischen 64K und 512K als Puffer sind schon gut.

    naja, ich glaube der tcp stack selber nimmt sich pro socket maximal 32K für den sendebuffer (oder war das bei solaris so?). wichtig ist halt, dass der immer schön voll ist, viel mehr kann man nicht machen.
    🙂



  • Winsock selbst hat unabhängig vom TCP/IP-Stack auch nochmal Puffer (siehe z.B. setsockopt() und SO_RCVBUF...).

    Und man sollte wirklich die Rückgabewerte von send und recv prüfen 😉



  • geeky schrieb:

    Winsock selbst hat unabhängig vom TCP/IP-Stack auch nochmal Puffer (siehe z.B. setsockopt() und SO_RCVBUF...).

    das ist doch bestimmt der gleiche buffer, ansonsten wär's ja doppelt gemoppelt und mit unnötigen buffer-umschaufeleien verbunden...
    🙂



  • hustbaer schrieb:

    send(..., 10, 0) verschickt nicht 10 Byte, sondern soviel wie der TCP/IP Stack gerade lustig ist, also 1 bis 10 Byte (blocking) oder 0 bis 10 Byte (non-blocking).

    Im Blocking-Modus wartet send immer bis alles weitergereicht wurde.



  • so neue client/server sind fertig und über netzwerk funktionierts mal super 🙂 also schnell und ohne fehler. leider kann ichs noch nicht über internet testen. ich melde mich sobald ichs testen konnte.

    vielen dank,
    mfg
    mitos



  • ok also es funktioniert ab einem buffer von 4096 byte nicht mehr einwandfrei:

    da kommen dann zukurze strings an, send gibt error zurück.
    ich versuche jetzt mal sie send errors zu verhindern. Was ist sonst noch falsch?
    😕

    code client:
    main.cpp

    #include "header.h"
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
    
    FILE* fcrefile=NULL;
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
    
       HWND         hWnd;
       MSG          msg;
       WNDCLASSEX   wndclassex = {0};
    
       wndclassex.cbSize        = sizeof(WNDCLASSEX);
       wndclassex.style         = CS_HREDRAW | CS_VREDRAW;
       wndclassex.lpfnWndProc   = WndProc;
       wndclassex.cbClsExtra    = 0;
       wndclassex.cbWndExtra    = 0;
       wndclassex.hInstance     = hInstance;
       wndclassex.hIcon         = LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(0));
       wndclassex.hCursor       = LoadCursor (NULL, IDC_ARROW);
       wndclassex.hbrBackground = (HBRUSH)(COLOR_WINDOW);
       wndclassex.lpszMenuName  = NULL;
       wndclassex.lpszClassName = szAppName;
       wndclassex.hIconSm       = wndclassex.hIcon;
    
       if (!RegisterClassEx (&wndclassex))
       {
          MessageBox (NULL,"fehler beim registrieren!",
                      szAppName, MB_ICONERROR);
          return 0;
       }
    
       int resX=GetSystemMetrics(SM_CXSCREEN);
       int resY=GetSystemMetrics(SM_CYSCREEN);
    
       hWnd = CreateWindowEx (/*WS_EX_OVERLAPPEDWINDOW*/0, 
                      szAppName, 
                      szAppName, 
                      WS_SYSMENU|WS_MINIMIZEBOX, 
                      (resX)/2-(x/2),                    
                      (resY)/2-(y/2),       
                      x,               
                      y,                 
                      NULL, 
                      NULL,          
                      hInstance,             
                      NULL); 
    
       ShowWindow (hWnd, iCmdShow);
       UpdateWindow (hWnd);
    
       while (GetMessage (&msg, NULL, 0, 0))
       {
          TranslateMessage (&msg);
          DispatchMessage (&msg);
       }
       return msg.wParam;
    }
    
    LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    
       switch (message)
       {
       case WM_CREATE:
    	   {
    		  ConnectToServer(hWnd);
    		  fcrefile=fopen("testtemp.exe","wb");
    
    		  break;
    	   }
    
       case WM_COMMAND:
    	   {
    		  /* if(lParam==(LPARAM)hEditFilter)
    		   {
    
    		   }*/
    		   break;
    	   }
    	case TCP_SOCKET_MSG:
    		{
    			if (WSAGETSELECTERROR(lParam)) 
    				return -1;
    			TMP_Socket = (SOCKET)wParam;
    
    			switch (WSAGETSELECTEVENT(lParam))
    			{
    				case FD_READ:
    				{
    					ZeroMemory(recv_buffer,MAX_BUFLEN);
    					laenge = recv(TMP_Socket, recv_buffer,4,0);
    
    					if(laenge<0)
    						break;
    
    					recv_buffer[laenge]='\0';
    
    					laenge=atoi(recv_buffer);
    
    					buflaenge = recv(TMP_Socket, recv_buffer,laenge,0);
    
    					recv_buffer[buflaenge]='\0';
    
    					if(buflaenge!= laenge)
    						MessageBox(hWnd,"buflaenge!=laenge",recv_buffer,0);
    
    					if(!strcmp(recv_buffer,"][ende]["))
    					{
    						fclose(fcrefile);
    						SetWindowText(hWnd,"finito");
    					}
    					else
    					{
    						for(int i=0; i<laenge; i++)
    							fputc(recv_buffer[i],fcrefile);
    
    						sendV(TMP_Socket,"get");
    					}
    
    					break;
    				}
    
    				case FD_CLOSE:
    				{
    					closesocket(TMP_Socket);
    					break;
    				}
    			}
    			break;
    		}
       case WM_TIMER:
    	   {
    
    		   break;
    	   }
       case WM_DESTROY:
    	   {
    			PostQuitMessage (0);
    			return (0);
    	   }
       }
    
       return DefWindowProc (hWnd, message, wParam, lParam);
    }
    

    header.h

    #include <windows.h>
    #include <windef.h>
    #include <stdio.h>
    #undef _WINDOWS_
    #include <afxsock.h>
    
    #define TCP_SOCKET_MSG WM_APP+21
    #define TCP_Port 36953
    #define MAX_BUFLEN 9000 ///////////////// DIE ALLES ENTSCHEIDENDE BUFFERGROESSE
    
    static char szAppName[] = "fileclient";
    static int x=500;
    static int y=500;
    
    int laenge;
    int buflaenge;
    char buffer[MAX_BUFLEN];
    char recv_buffer[MAX_BUFLEN];
    
    static SOCKET TCP_Socket=INVALID_SOCKET;
    static SOCKET TMP_Socket=INVALID_SOCKET;
    static SOCKADDR_IN TCPServer={0};
    static SOCKADDR_IN TCPClient={0};
    
    int startWinsock(void)
    {
    	WSADATA wsa;		
    	return WSAStartup(MAKEWORD(2,0),&wsa);
    }
    
    bool ConnectToServer(HWND hWndS)
    {
    
    	bool Connected=false;
    	startWinsock();
    	if(TCP_Socket!= INVALID_SOCKET)
    		closesocket(TCP_Socket);
    
    	TCP_Socket = socket(AF_INET,SOCK_STREAM,0);
    
    	TCPServer.sin_family = AF_INET; 
    	TCPServer.sin_addr.s_addr= inet_addr("127.0.0.1");
    
    	TCPServer.sin_port = htons(TCP_Port);
    
    	int err=connect(TCP_Socket,(SOCKADDR FAR *)&TCPServer,sizeof(SOCKADDR_IN));
    
    	WSAAsyncSelect(TCP_Socket, hWndS, TCP_SOCKET_MSG, FD_READ | FD_CLOSE);
    
    	if (SOCKET_ERROR == err) 
    	{ 
    		MessageBox(hWndS,"Es konnte keine Verbindung zum Server hergestellt werden\nVersuchen Sie sich später erneut zu verbinden", "Error", MB_ICONERROR|MB_OK);
    		Connected=false;
    	} 
    	else
    	{
    		Connected=true;
    	}
    
    	return Connected;
    }
    
    int sendV(SOCKET TCP_SOC,char* BufferToSend)
    {
    	char buffer[MAX_BUFLEN];
    	int x=0;
    
    	int buflaenge=0;
    	buflaenge=strlen(BufferToSend);
    	if(buflaenge>MAX_BUFLEN)
    		return -1;
    
    	sprintf(buffer,"%04i%s",buflaenge,BufferToSend);
    
    	return send(TCP_SOC,buffer,buflaenge+4,0);
    
    }
    
    void CommandWorker(char* buffer)
    {
    	//MessageBox(0,buffer,0,0);
    
    }
    

    code server:
    main.cpp

    #include "header.h"
    
    FILE *sendfile=NULL;
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
    
       HWND         hWnd;
       MSG          msg;
       WNDCLASSEX   wndclassex = {0};
    
       wndclassex.cbSize        = sizeof(WNDCLASSEX);
       wndclassex.style         = CS_HREDRAW | CS_VREDRAW;
       wndclassex.lpfnWndProc   = WndProc;
       wndclassex.cbClsExtra    = 0;
       wndclassex.cbWndExtra    = 0;
       wndclassex.hInstance     = hInstance;
       wndclassex.hIcon         = LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(0));
       wndclassex.hCursor       = LoadCursor (NULL, IDC_ARROW);
       wndclassex.hbrBackground = (HBRUSH)(COLOR_WINDOW);
       wndclassex.lpszMenuName  = NULL;
       wndclassex.lpszClassName = szAppName;
       wndclassex.hIconSm       = wndclassex.hIcon;
    
       if (!RegisterClassEx (&wndclassex))
       {
          MessageBox (NULL,"fehler beim registrieren!",
                      szAppName, MB_ICONERROR);
          return 0;
       }
    
       int resX=GetSystemMetrics(SM_CXSCREEN);
       int resY=GetSystemMetrics(SM_CYSCREEN);
    
       hWnd = CreateWindowEx (/*WS_EX_OVERLAPPEDWINDOW*/0, 
                      szAppName, 
                      szAppName, 
                      WS_SYSMENU|WS_MINIMIZEBOX, 
                      (resX)/2-(x/2),                    
                      (resY)/2-(y/2),       
                      x,               
                      y,                 
                      NULL, 
                      NULL,          
                      hInstance,             
                      NULL); 
    
       ShowWindow (hWnd, iCmdShow);
       UpdateWindow (hWnd);
    
       while (GetMessage (&msg, NULL, 0, 0))
       {
          TranslateMessage (&msg);
          DispatchMessage (&msg);
       }
       return msg.wParam;
    }
    
    LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    
    static HWND hStaTime;
    
       switch (message)
       {
       case WM_CREATE:
    	   {
    		   hStaTime= CreateWindow("static",
    										"send time",
    										WS_VISIBLE|WS_CHILD,
    										30,30,80,40,
    										hWnd,
    										0,
    										((LPCREATESTRUCT) lParam)->hInstance,
    										0
    										); 
    		  StartServer(hWnd);
    		  sendfile=fopen("temp.exe","rb");
    
    		  break;
    	   }
    
       case WM_COMMAND:
    	   {
    		  /* if(lParam==(LPARAM)hEditFilter)
    		   {
    
    		   }*/
    		   break;
    	   }
    	case TCP_SOCKET_MSG:
    		{
    			if (WSAGETSELECTERROR(lParam)) 
    				return -1;
    			TMP_Socket = (SOCKET)wParam;
    
    			switch (WSAGETSELECTEVENT(lParam))
    			{
    				case FD_READ:
    				{
    					ZeroMemory(recv_buffer,MAX_BUFLEN);
    
    					laenge = recv(TMP_Socket, recv_buffer,4,0); //holt sich die länge des kommenden strings
    
    					if(laenge<0)
    						break;
    
    					recv_buffer[laenge]='\0';
    
    					laenge=atoi(recv_buffer);
    
    					buflaenge = recv(TMP_Socket, recv_buffer,laenge,0);
    
    					recv_buffer[buflaenge]='\0';
    
    					if(buflaenge!= laenge)
    						MessageBox(hWnd,"buflaenge!=laenge","error",0);
    
    					if(!strcmp(recv_buffer,"get"))
    					{
    						for(int i=0; i<(MAX_BUFLEN-5); ++i)
    						{
    							if(!feof(sendfile))
    							readbuf[i]=fgetc(sendfile);
    							else
    							{i--;
    							break;
    							}
    						}
    
    						if(!ferror(sendfile)&&i>0)
    						{
    							char sbuffer[MAX_BUFLEN];
    							sprintf(sbuffer,"%04i",i);
    
    							for(int j=4; j<(i+4); j++)
    								sbuffer[j]=readbuf[j-4];
    							if(send(TMP_Socket,sbuffer,i+4,0)!=i+4)
    								MessageBox(0,"send error",0,0);
    						}
    
    						if(feof(sendfile))
    						{
    							send(TMP_Socket,"0008][ende][",12,0);
    							KillTimer(hWnd,0);
    						}
    						}
    
    					break;
    				}
    				case FD_ACCEPT:
    				{
    					TMP_Socket= accept(TCP_Socket,(SOCKADDR *)&TCPClient,&nSize);					
    
    					if(TMP_Socket==INVALID_SOCKET)
    						MessageBox(0,"error verbunden",0,0);
    
    					for(int i=0; i<(MAX_BUFLEN-5); ++i)
    					{
    						if(!feof(sendfile))
    						readbuf[i]=fgetc(sendfile);
    						else
    						{i--;
    						break;
    						}
    					}
    
    					if(!ferror(sendfile)&&i>0)
    					{
    						char sbuffer[MAX_BUFLEN];
    						sprintf(sbuffer,"%04i",i);
    
    						for(int j=4; j<(i+4); j++)
    							sbuffer[j]=readbuf[j-4];
    						if(send(TMP_Socket,sbuffer,i+4,0)!=i+4)
    							MessageBox(0,"send error",0,0);
    					}
    					else
    						MessageBox(0,"fehler beim lesen der datei",0,0);
    					SetTimer(hWnd,0,1000,0);
    					SetWindowText(hStaTime,"0");
    					if(feof(sendfile))
    					{
    						send(TMP_Socket,"0008][ende][",12,0);
    						KillTimer(hWnd,0);
    					}
    
    					break;
    
    				}
    				case FD_CLOSE:
    				{
    					closesocket(TMP_Socket);
    					break;
    				}
    			}
    			break;
    		}	
       case WM_TIMER:
    	   {
    		   ++istime;
    		   char buf[64];
    		   sprintf(buf,"%i",istime);
    		   SetWindowText(hStaTime,buf);
    
    		   break;
    	   }
       case WM_DESTROY:
    	   {
    			PostQuitMessage (0);
    			return (0);
    	   }
       }
    
       return DefWindowProc (hWnd, message, wParam, lParam);
    }
    

    header.h

    #include <windows.h>
    #include <windef.h>
    #include <stdio.h>
    #undef _WINDOWS_
    #include <afxsock.h>
    
    #define TCP_SOCKET_MSG WM_APP+21
    #define TCP_Port 36953
    #define MAX_BUFLEN 9000 ///////////////// DIE ALLES ENTSCHEIDENDE BUFFERGROESSE
    
    static char szAppName[] = "fileserver";
    static int x=500;
    static int y=500;
    
    int err;
    int laenge;
    int buflaenge;
    int istime=0;
    char buffer[MAX_BUFLEN];
    char recv_buffer[MAX_BUFLEN];
    char readbuf[MAX_BUFLEN];
    
    static SOCKET TCP_Socket=INVALID_SOCKET;
    static SOCKET TMP_Socket=INVALID_SOCKET;
    static SOCKET TMP_Friend=INVALID_SOCKET;
    static SOCKADDR_IN TCPServer={0};
    static SOCKADDR_IN TCPClient={0};
    
    int nSize=sizeof(SOCKADDR_IN);
    
    int startWinsock(void)
    {
    	WSADATA wsa;		
    	return WSAStartup(MAKEWORD(2,0),&wsa);
    }
    
    void StartServer(HWND hWnds)
    {
    	startWinsock();
    
    	if(TCP_Socket!= INVALID_SOCKET)
    		closesocket(TCP_Socket);
    
    	TCP_Socket = socket(AF_INET,SOCK_STREAM,0);
    
    	TCPServer.sin_family = AF_INET; 
    	TCPServer.sin_addr.s_addr = htonl(INADDR_ANY); 
    	TCPServer.sin_port = htons(TCP_Port); 
    
    	err = bind(TCP_Socket,(SOCKADDR FAR *)&TCPServer,sizeof(SOCKADDR_IN)); 
    
    	if (SOCKET_ERROR == err) 
    	{ 
    		MessageBox(hWnds,"Failed to start TCP-Server", "Error", MB_OK);
    	} 
    
    	err =listen(TCP_Socket,SOMAXCONN);
    
    	WSAAsyncSelect(TCP_Socket, hWnds, TCP_SOCKET_MSG, FD_ACCEPT | FD_READ | FD_CLOSE);
    }
    
    int sendV(SOCKET TCP_SOC,char* BufferToSend)
    {
    	char buffer[MAX_BUFLEN];
    	int x=0;
    
    	int buflaenge=0;
    	buflaenge=strlen(BufferToSend);
    	if(buflaenge>MAX_BUFLEN)
    		return -1;
    
    	sprintf(buffer,"%04i%s",buflaenge,BufferToSend);
    
    	return send(TCP_SOC,buffer,buflaenge+4,0);
    
    }
    
    void CommandWorker(char* buffer)
    {
    
    }
    

    so ich hoffe ihr könnt den fehler finden, bin für alles offen.
    Sobald sich der client verbunden hat, schließt sich der server, also beendet sich selbst 😞 es kommt auch kein error...
    🙂
    danke schonmal,
    mfg



  • Undertaker schrieb:

    geeky schrieb:

    Winsock selbst hat unabhängig vom TCP/IP-Stack auch nochmal Puffer (siehe z.B. setsockopt() und SO_RCVBUF...).

    das ist doch bestimmt der gleiche buffer, ansonsten wär's ja doppelt gemoppelt und mit unnötigen buffer-umschaufeleien verbunden...
    🙂

    msdn schrieb:

    SO_RCVBUF int Specifies the total per-socket buffer space reserved for receives. This is unrelated to SO_MAX_MSG_SIZE and does not necessarily correspond to the size of the TCP receive window.

    WinSock ist ja noch ne Schicht über TCP/IP und kann statt TCP/IP auch was anderes als drunterliegende Schicht nutzen. Von daher wird Buffer rumkopiererei eh nötig sein 😉



  • hmm also ich hab jetzt noch ein bisschen rumprobiert, jetzt läufts über netzwerk auch einwandfrei mit 32k buffer 🙂 falls jemand den code doch noch sehen möchte eventuell sagen...

    danke an alle,
    mfg
    mitos



  • Eieiei ist der Code schlecht. :kotz:



  • naja sowas kannst du dir echt sparen... wiealt bist du? 14? 😃
    Nehme konstruktive kritik allerdings gern an...
    mfg



  • Im Blocking-Modus wartet send immer bis alles weitergereicht wurde.

    Das ist das beobachtbare Verhalten, aber nicht das dokumentierte Verhalten.
    Wer sich nach beobachtbarem Verhalten richten möchte, und damit riskiert dass es irgendwann irgendwo nichtmehr geht... bittesehr. Ich richte mich nach der Doku.

    p.S.: falls es irgendwo im Kleingedruckten in der Doku stehen sollte würde es mich interessieren den entsprechenden Teil zu lesen, in dem Fall würde ich mich über nen Link/Hinweis freuen.



  • naja also er funktioniert jetzt doch nicht 😞 oft gehts oft nicht, exe dateien mag er überhaupt nicht gern verschicken...
    Hat niemand n tutorial bzw. ein projekt, da wos richtig gut funktioniert!?

    danke,
    mfg



  • geeky schrieb:

    Undertaker schrieb:

    geeky schrieb:

    Winsock selbst hat unabhängig vom TCP/IP-Stack auch nochmal Puffer (siehe z.B. setsockopt() und SO_RCVBUF...).

    das ist doch bestimmt der gleiche buffer, ansonsten wär's ja doppelt gemoppelt und mit unnötigen buffer-umschaufeleien verbunden...
    🙂

    msdn schrieb:

    SO_RCVBUF int Specifies the total per-socket buffer space reserved for receives. This is unrelated to SO_MAX_MSG_SIZE and does not necessarily correspond to the size of the TCP receive window.

    WinSock ist ja noch ne Schicht über TCP/IP und kann statt TCP/IP auch was anderes als drunterliegende Schicht nutzen. Von daher wird Buffer rumkopiererei eh nötig sein 😉

    klar, socket sind die benutzerstelle zu TCP, aber trotzdem glaube ich nicht, dass sockets und TCP getrennte buffer haben. was hätte das für einen sinn? es wird vielmehr so sein, dass ein socket seine buffer (für send und recv) verwaltet und TCP am anderen ende hängt und daten ausliest bzw. hineinschreibt.
    🙂



  • versuchs doch erst mal mit blocking sockets zu realisieren, ist einfacher zu durchblicken.



  • naja ich kenn mich bei den arten nicht so aus... was genau ist der blocking socket? bzw. wie kann ich ihn realisieren?



  • mitos, ich hab' dir schon gesagt was das Problem ist.
    Der letzte Code den du gepostet hast zeigt dass den den Hinweis ignoriert hast.
    Was willst du jetzt?
    Noch mehr Vorschläge die du dann nicht umsetzt?



  • ich habs versucht zu beachten...! allerdings gibt send() bei mir immer SOCKET_ERROR zurück, wenn ich übers internet verschicke und der buffer größer als 2000 ist.



  • hast du schon die doku von WSAAsyncSelect durchgelesen?



  • jo hab ich, http://msdn2.microsoft.com/en-us/library/ms741540.aspx
    ich versteh jetzt nicht genau auf was du hinauswillst... ich hab die funktion ja verwendet...


Anmelden zum Antworten