Dateien über Winsock versenden



  • warum trennzeichen?, du weist duch wie gross die bytes sind.
    du baust ein stream auf wie du es möchtest.

    ganz "grass gesehen"

    struct IO
    {
      int  b1;
      UINT b2;
      char s[255];
    };
    IO   io;
    BYTE x[1024];
    memcpy(x, &io, sizeof(IO));   //sende x;
    
    //empfänger
    BYTE y[1024];                 //empfange y
    IO   out;
    
    memcpy(&out, y, sizeof(IO));
    


  • Also wenn ich zum Beispiel den Inhalt "Halloduda" einer Textdatei sende,
    müsste das so aussehen:

    9Halloduda

    Dem Empfänger müsste ich also "sagen", dass das 1. Zeichen die Dateigröße beinhaltet. Daraufhin liest er die nächsten Zeichen und speichert sie in eine Datei.

    Aber die zu sendende Datei ist ja nicht immer gleich groß! Mal 33KB, mal 55KB...
    Woher soll der Empfänger dann wissen, bis wohin der empfangene Stream die Dateigröße beinhaltet - und ab wo der eigentliche Dateiinhalt beginnt?

    Das geht (meiner Meinung nach) nur mit Trennzeichen 😕
    oder liege ich da falsch? 😞



  • du liegst doch schon richtig.

    //stream
    struct STREAM
    {
      size_t nlen;
      char*  str;
    };
    
    STREAM st;
    
    st.str=/*zeiger auf deine dateiinhalt*/
    st.nlen=strlen(st.str);               //oder anders
    
    //dein strem hat nun die gesamte länge st.nlen+sizeof(size_t)
    //abstrakt gesehen
    
    BYTE buf[1024]; 
    
    size_t pos=0; BYTE* b=buf;
    
    memcpy(b, &st.nlen, sizeof(size_t));
    b +=sizeof(size_t);
    
    while (pos != st.nlen)
    {
      size_t n=1024-(b-buf);
      memcpy(b, str+pos, n);
      // send 1024 bytes
      pos +=n; b=buf;
    }
    

    es gibt natürlich noch viele andere wege, z.b ohne buffer
    man muss aufpassen du kannst nur int=INT_MAX zeichen auf einmal senden

    der empfänger sieht vom prinzip gleich aus

    BYTE buf[1024]; size_t pos=0;
    bool blen=false; 
    STREAM st={0,0};
    
    while (blen && pos != st.nlen)
    {
      int n=recv(0, (char*)buf, 1024, 0);
      if (n == SOCKET_ERROR) break;
      char* b=buf;
      if (!blen)
      {
        // etwas übertrieben man hoft ja auf min 4 byte
        int len= pos+n >= sizeof(size_t)? sizeof(size_t)-pos:n;
        memcpy(&st.nlen+pos, buf, len);
        pos +=len;
        blen= pos != sizeof(size_t);
        if (!blen) continue; 
        // jetzt beginnt das char*
        n -=len; b +=len;
        pos=0;
      }
      if (n)
      {
        //in b mit n bytes steht deine teil (stream) datei
        //den du jetzt mit einem offset von pos wieder in deine 
        //datei schreiben kannst
    
        pos +=n;
      }
    }
    

    was besseres viel mir jetzt auch nicht ein



  • Hi vdittrich!
    Sorry, dass ich noch nicht so viel von dem Code verstehe - bin leider noch ein
    (totaler 😕) Newbie. Die Frage ist mir zwar fürchterlich peinlich 😞
    - aber könntest du mir sagen, wie und wo ich send und CreateFile in dem Code benutzen muss; (und ob ich den Code dann komplett in mein Projekt übernehmen kann)?

    Habe leider noch nicht so viel Ahnung von "memcpy" und "size_t" 🙄

    Vielen, vielen Dank im voraus!
    (Diesmal ohne Rächtschraibfähla 🤡)



  • ich denke du solltest dich erst mal mit was einfacheren beschäftigen.

    bei http://zotteljedi.de/doc/socket-tipps.html kannst du dir den kompl. source eines ftp-socket runterladen, das ist doch das was du suchst.

    fertige lösungen wirst du von keinen hier bekommen.



  • Hab ich mir schon gedacht, dass man hier keine fertigen Codes bekommt 🙄

    Es ist doch praktisch möglich, die Datei und die Dateigröße getrennt mit einem | in einem Stream an den Server zu senden.

    Um die Datei und die Dateigröße jeweils in einem String abzuspeichern, kann ich doch dann eine "selbstgeschriebene" 😃 explode - Funktion benutzen:

    std::string explode(char trennzeichen, std::string str, int part)
                       {
                         std::string output;
                          if (part == 0) // Wenn der erste Part gesucht wird
                                         // müssen viele komplizuierte schritte nicht gemacht werden
                             {
                                  string::size_type pos1 = str.find_first_of(trennzeichen);
                                  output = str.substr(0,pos1);
                             }
                             else
                             {
                                 /* Als erstes muss die Anzahl der Trennzeichen in dem
                                    zu Teilendem String festgestellt werden, dies geschieht in
                                    einer Schleife, und wenn die Anzahl (int i) mit (int) part (-1)
                                    übereinstimmt wird die Postition ausfindig gemacht.
                                 */
                                 int s_lengh = strlen(str.c_str());
                                 int match_c = 0;
    
                                 for (int i=0;i<s_lengh;i++)
                                     {
    
                                       if (str[i] == trennzeichen)
                                          {
                                           match_c++;
                                            if (match_c == part)
                                               {
                                                 std::string str_2 = str.substr(i+1, 1000);
                                                 string::size_type pos2 = str_2.find_first_of(trennzeichen);
                                                 output = str_2.substr(0,pos2);
                                               }
                                          }
                                     }
                             }
                         return output;
                       }
    

    ... oder nicht?



  • Wozu so umständlich? Wenn du die Dateigröße direkt als int am Anfang überträgst sind das doch immer 4 Bytes 😉



  • Wirklich? Na, wenn das so ist 🙂
    - Aber mit welchen Funktionen (die nicht so kompliziert sind 🙄)
    kann ich denn dann meinen empangenen Buffer "auseinander nehmen"?



  • Du liest einfach das erste Byte aus (und wandelst es wieder in einen int um - anschließend setzt du den Pointer um einen Byte weiter 🙂



  • Schaue dir das mal an

    //receiver
    	while (ret != SOCKET_ERROR)
    	{
    		ret = recv (*connectedSocket, Buffer,(2*sizeof(int)),NULL);
    
    		if(ret == (2*sizeof(int)))
    		{
    			memcpy(&iCommandNr,Buffer,sizeof(int));
    			memcpy(&iRecBufferSize,&Buffer[sizeof(int)],sizeof(int));
    			cRecBuffer = new char[iRecBufferSize];
    
    			if(0 != iRecBufferSize)
    				recv (*connectedSocket, cRecBuffer,iRecBufferSize,NULL);
    
    			wsprintf(port,"%d",*connectedSocket);
    			iPos = m_This->m_listL.InsertItem(0,port);
    			m_This->SetLVMStructureL(iPos,1,cPlayerName);
    			m_This->SetFunctionName(iCommandNr,iPos);
    
    			m_This->cManagerServer.SendBuffer(iCommandNr,iRecBufferSize,cRecBuffer,&cSendBuffer,port);
    
    			delete [] cRecBuffer;
    			char * SendeBuffer;
    			char indicator = -1;
    			SendeBuffer = new char [((2*sizeof(int))+iRecBufferSize)+1];
    			memcpy(SendeBuffer,&iCommandNr,sizeof(int));
    			memcpy(&SendeBuffer[sizeof(int)],&iRecBufferSize,sizeof(int));
    			memcpy(&SendeBuffer[(2*sizeof(int))],cSendBuffer,iRecBufferSize);
    			memcpy(&SendeBuffer[(2*sizeof(int))+iRecBufferSize],&indicator,1);
    
    			send(*connectedSocket,SendeBuffer,(2*sizeof(int)), NULL);
    
    			int iSendData = 0;
    			int icount = 0;
    			int i = 0;
    			int ISize = iRecBufferSize+1;
    			bool bFirst = true;
    			do
    			{
    				if(1024 < (iRecBufferSize-icount))
    					iSendData = 1024;
    				else
    					iSendData = ISize-icount;
    				char szData = 1;
    				do
    				{
    					i = send(*connectedSocket,&SendeBuffer[(2*sizeof(int))+icount],iSendData, NULL);
    					ret = recv (*connectedSocket, Buffer,1,NULL);
    					if(ret != -1)
    						memcpy(&szData,Buffer,1);
    				}while(szData == 1 && ret != SOCKET_ERROR && ret != 0);
    
    				if(bFirst && i != 0)
    				{
    					bFirst = false;
    					icount--;
    				}
    				icount += i;
    				if(i == 0)
    					icount--;
    			}
    			while(icount != iRecBufferSize && ret != SOCKET_ERROR && ret != 0);
    			delete [] SendeBuffer;
    			delete [] cSendBuffer;
    			if(FSetClientName == iCommandNr)
    			{
    				CString ctmp;
    				ctmp = m_This->cManagerServer.GetClientName(port);
    				strcpy(cPlayerName,ctmp.GetBuff(ctmp.GetLength()));
    				ctmp.ReleaseBuffer();
    			}
    			continue;
    		}
    
    		if (ret == 0 || ret == SOCKET_ERROR)
    		{
    		}
    	}
    
    //Sender
    DLLEXPORT virtual void Send(int ifunctionNo,int &ISize,char *cSendBuffer,char **cRecBuffer)
    	{
    		char * TransmitBuffer;
    
    		TransmitBuffer = new char[(2*sizeof(int)+ISize)];
    
    		memcpy(TransmitBuffer,&ifunctionNo,sizeof(int));
    		memcpy(&TransmitBuffer[sizeof(int)],&ISize,sizeof(int));
    		memcpy(&TransmitBuffer[(2*sizeof(int))],cSendBuffer,ISize);
    
    		if(0 > send(ssocket, TransmitBuffer,((2*sizeof(int))+ISize),NULL))
    		{
    			bConnected = false;	
    		}
    		else
    		{
    			char sbuffer[8];
    
    			recv (ssocket,sbuffer,(2*sizeof(int)), NULL);
    
    			memcpy(&ifunctionNo,sbuffer,sizeof(int));
    			memcpy(&ISize,&sbuffer[sizeof(int)],sizeof(int));
    			ISize++;
    
    			if(0 < ISize)
    			{
    
    				*cRecBuffer = new char[ISize];
    				char indicator = -1;
    				char *ptemp ;
    				int i = 0;
    				int icount = 0;
    				int iReaddata = 0;
    				int iSendData = 0;
    				bool bFirst = true;
    
    				memset(*cRecBuffer,0,ISize);
    
    				char *tmp = new char [ISize];
    				do
    				{
    					indicator = -1;
    					if(1024 < (ISize-icount))
    						iReaddata = 1024;
    					else
    					{
    						if( 0 == icount)
    							iReaddata = ISize-icount;
    						else
    							iReaddata = ISize-icount;
    					}
    					char *crecievebuffer = new char[iReaddata];
    					memset(crecievebuffer,0,iReaddata);
    					i = recv(ssocket,crecievebuffer,iReaddata,NULL);
    					if(i == -1)
    					{
    						indicator = 1;
    						i = WSAGetLastError();
    						i = 0;
    					}
    					while(-1 == send(ssocket, &indicator,1,NULL));
    					memcpy(&tmp[icount],crecievebuffer,i);
    
    					if(bFirst && i != 0)
    					{
    						bFirst = false;
    						icount--;
    					}
    					icount +=i;
    					if(i == 0)
    						icount--;
    					ptemp = tmp;
    					delete [] crecievebuffer;
    
    				}while(ptemp[icount] != -1);
    				memcpy(*cRecBuffer,tmp,ISize);
    				delete [] tmp;
    			}
    		}
    		delete [] TransmitBuffer;
    	};
    

    So mache ich es in einem TCP Server von mir

    edit: sfds



  • Igitt!!! Wie wär's mal mit Code-Tags???



  • Sorry werde ab jetzt code-tags verwenden .
    Danke ichbins



  • OK - hab den Filetransfer jetzt doch mit der selbstgeschriebenen explode-Funktion geschafft. Allerding klappt das ganze nur bis zum 1. "|" Zeichen in der Gif-Datei. Da ja in so einer GIF-Datei alle möglichen Buchstaben und Zeichen vorkommen, weis ich leider net, welches Zeichen ich als Trennzeichen benutzen kann. 😕



  • Habe eine Lösung gefunden!
    Bin gerade dabei, eine while-Schleife zu programmieren, die überprüft, ob noch mehr Zeichen nach dem | kommen.

    (So in etwa):

    char * abort = "no"; int count = 2;
    while (abort == "no")
    {
    	String part[count] = explode('|', buf, count);
    	const char * cpart[count] = part[count].c_str();
    
    	if (strcmp(cpart[count], "") == 0) {abort = "yes";}
    	else {part1 + cpart[count]; count++;}
    }
    

    Natürlich ist der Code völlig falsch 🙄
    Aber wie kann man eigentlich Strings nach so einem Prinzip erstellen lassen?
    Ihr wisst hoffentlich, was ich meine 🙄



  • @ichbins17: hast du einen tcp server geproggt? kannst du mir eventuell mal die source geben: surfman19@gmx.at

    wär klass...
    cu



  • Hi @all!
    Habe es jetzt mit folgendem Code realisiert. Das Problem ist nur, dass keine Messagebox ausgegeben wird 😞

    int count = 3; char * abort = "no";
    			string part1 = explode('|', buf, 0);
    			string part2 = explode('|', buf, 1);
    			string part3;
    
    			const char * checkfile = part1.c_str();
    			const char * cfilesize = part2.c_str();
    
    			while (strcmp(abort, "no") == 0)
    			{
    				string apart = explode('|', buf, count);
    				const char * capart = apart.c_str();
    
    				if (strcmp(capart, "") != 0) {part3 + capart; count++;}
    				else {abort = "yes";}
    			}
    
    			const char * data = part3.c_str();
    			MessageBox(NULL, data, NULL, NULL);
    


  • deine messagebox weis nicht was sie tun soll (letzter parameter)
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/dialogboxes/dialogboxreference/dialogboxfunctions/messagebox.asp

    so sollte es gehen

    MessageBox(NULL, part3.c_str(), "info", MB_OK);
    


  • Geht leider immer noch nicht 😞

    Zu meinem Code:
    Ich meinte natürlich

    if (strcmp(capart, "") != 0) {part3 + apart; count++;}
    


  • wenn du schon std::string benutz kannst du doch auch die einbauten funktionen benutzen siehe http://cplus.kompf.de/artikel/strings.html
    warum machst du abort nicht boolisch ?

    probiert es mal so
    [cpp]
    while (strcmp(abort, "no") == 0)
    {
    string apart = explode('|', buf, count);

    if(apart.compare("") != 0) // oder apart.size() > 0
    {
    part3 += apart;
    ++count;
    }
    else
    abort = "yes";

    }

    MessageBox(NULL, part3.c_str(), "info", MB_OK);
    [/cpp]



  • Geil! Es klappt endlich!
    Vielen Dank für die schnelle Antwort und den Codeschnipsel!
    Nach dem letzten Zeichen erscheint in der Messagebox zwar noch ein bisschen Müll - aber das bekomm´ ich bestimmt auch noch hin 😃 🙄

    THX Maxime

    Achja - bevor ich´s vergesse:
    VIELEN DANK AN ALLE, DIE AUF MEINE FRAGEN GEANTWORTET HABEN!
    IHR HABT MIR SEHR WEITERGEHOLFEN! 👍


Anmelden zum Antworten