Socket Kommunikation Befehl: select



  • moin

    hab da nen Problem:

    Ich hab nen Drucker dem schick ich ein Label das er abarbeiten soll

    <STX>TZTextname.00I;10<CR>Daten<CR><ETX>

    Wenn ich diesen Befehl sende bekomm ich ein <ACK> als antwort
    und wenn der Drucker gedruckt hat: <STX>1Ok<ETX>

    Heist ich sende per Befehl: "Set_VTEXT"
    die variabelen Daten

    und will per Befehl: "IsPrint"
    abfragen ob auf dem Socket Daten liegen -> diese abholen -> und überprüfen ob die Daten des Druckers mit den erwarteten Daten übereinstimmen um zu sagen er hat gedruckt.

    Mein Problem war bisher das das <ACK> als eine Antwort kam und irgendwann später <STX>1Ok<ETX> als Antwort kam und mein Programm per recv() ewig auf die Antwort gewartet hat und dadurch mein Programm geblockt hat...

    nun hab ich gelesen das man mit Hilfe des Befehls select() nachfragen kann ob überhaupt erstmal was auf dem Socket liegt was man mit recv() abholen kann

    also hab ich das versucht einzubauen ...
    nur leider liefert mir das select immer nur eine fehlermeldung (10038) zurück...

    was mach ich falsch??

    bool CMainFrame::cmdServer(CString cmd, CString ip, int port){
    	/////////////Connect Anfang////////////////
    	long rc;
    	SOCKET s;
    	SOCKADDR_IN addr;
    	bool ret=false;
    	inUse = true;
    	FD_SET fdSet;
    
    	CStringArray r_cmd;
    	int iNum_CMD = ParseTokens( r_cmd, cmd, "|");
    	CString * param;
    	int anz_param = 0;
    	if(iNum_CMD>1){
    		cmd = r_cmd[0];
    		param = new CString[iNum_CMD-1];
    
    		anz_param=iNum_CMD-1;
    
    		for(int cmd_i=0; cmd_i<(iNum_CMD-1); cmd_i++){
    			param[cmd_i] = r_cmd[cmd_i+1];
    		}
    	}
    
    	rc=startWinsock();
    	if(rc!=0) {
    		CString str;
    		str.Format("%d",rc);
    	    AfxMessageBox("Fehler: startWinsock, fehler code: "+str);
    		WSACleanup();
    		ret=false;
    		return ret;
    	} 
    
    	s=socket(AF_INET,SOCK_STREAM,0);
    	if(s==INVALID_SOCKET) {
    		CString str;
    		str.Format("%d",WSAGetLastError());
    		AfxMessageBox("Fehler: Der Socket konnte nicht erstellt werden, fehler code: "+str);
    		closesocket(s);
    		WSACleanup();
    		ret=false;
    		return ret;
    	}
    
    	memset(&addr,0,sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten 
    	addr.sin_family=AF_INET;
    	addr.sin_port=htons(port);
    	addr.sin_addr.s_addr=inet_addr(ip);
    
    	rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
    	if(rc==SOCKET_ERROR){
    		CString str;
    		str.Format("%d",WSAGetLastError());
    		AfxMessageBox("Fehler: connect gescheitert, fehler code: "+str);
    		closesocket(s);
    		WSACleanup();
    		ret=false;
    		//OnVerbindungVerbindungtrennen();
    		return ret;
    	} 
    	/////////////Connect Ende////////////////	
    
    	/////////////Befehle Anfang////////////////
    
    	FD_SET(s,&fdSet);
    
    	if(cmd.CompareNoCase("BLUHM_ON")==0){
    		int len=0;
    		CString cmd="";
    		CString cmd_return="";
    		//Ok<CR>
    		CString cmd_return_soll="4F 6B 0D";
    
    		FD_ZERO(&fdSet); // Inhalt leeren
    
    		CString cmd_erg;
    		// <ESC> + C1 + <CR>
    		cmd_erg.Format("%cC1%c",ConvertStringHexToChar("1B"), ConvertStringHexToChar("0D"));
    
    		len=cmd_erg.GetLength()+1;
    		char * buf = new char[len];
    		memcpy(buf,cmd_erg, len);
    
    		ret=SendBlock(s, buf,len);
    
    		char *recvbuffer=NULL;
    		recvbuffer = new char[1024];
    		rc=recv(s,recvbuffer,1024,0);
    		if(rc==SOCKET_ERROR) {
    			CString str;
    			str.Format("%d",WSAGetLastError());
    			AfxMessageBox("Fehler: recvfrom, fehler code: "+str);
    		} else {
    			recvbuffer[rc]='\0';
    			CString tmp="", tmp2="";
    
    			for(int xx=0; xx<rc; xx++){
    				tmp.Format("%x", recvbuffer[xx]);
    				if(tmp.GetLength()<2){
    					tmp="0"+tmp;
    				}
    				if(tmp.GetLength()>2){
    					CString tmp3="";
    					for(int iy=tmp.GetLength()-2; iy<tmp.GetLength(); iy++){
    						tmp3=tmp3+tmp.GetAt(iy);
    					}
    					tmp=tmp3;
    				}
    				if(xx<(rc-1)){
    					tmp=tmp+" ";
    				}
    				tmp2=tmp2+tmp;
    			}
    			if(tmp2.CompareNoCase(cmd_return_soll)!=0){
    				CString meldung;
    				meldung.Format("Fehler: %s",tmp2);
    				AfxMessageBox(meldung);
    			}else{
    				ret=TRUE;
    				CString meldung;
    				meldung.Format("Kein Fehler: %s",tmp2);
    				AfxMessageBox(meldung);
    			}
    		}
    		delete[] recvbuffer;
    		delete[] buf;
    	}
    
    	if(cmd.CompareNoCase("BLUHM_SET_VTEXT")==0){
    		int len=0;
    		CString cmd="";
    		// <ACK>
    		CString cmd_return_soll_1="06";
    		// <STX>1Ok<ETX>
    		CString cmd_return_soll_2="02 31 4F 4B 03";
    
    		CString lm=param[0];
    		//CString lm="GS1.00I";
    
    		CString cmd_erg;
    		// <STX>TZTextname.00I;10<CR><ETX>
    		cmd_erg.Format("%cTZ%s;10%c",ConvertStringHexToChar("02"), lm, ConvertStringHexToChar("0D"));
    
    		for(int i=1; i<anz_param; i++){
    			cmd_erg=cmd_erg+param[i]+ConvertStringHexToChar("0D");
    		}
    
    		cmd_erg = cmd_erg + ConvertStringHexToChar("03");
    
    		len=cmd_erg.GetLength()+1;
    		char * buf = new char[len];
    		memcpy(buf,cmd_erg, len);
    
    		ret=SendBlock(s, buf,len);
    
    		char *recvbuffer=NULL; 
    		recvbuffer = new char[1024];
    		rc=recv(s,recvbuffer,1024,0);
    		if(rc==SOCKET_ERROR) {
    			CString str;
    			str.Format("%d",WSAGetLastError());
    			AfxMessageBox("Fehler: recvfrom, fehler code: "+str);
    		} else {
    			recvbuffer[rc]='\0';
    			CString tmp="", tmp2="";
    
    			for(int xx=0; xx<rc; xx++){
    				tmp.Format("%x", recvbuffer[xx]);
    				if(tmp.GetLength()<2){
    					tmp="0"+tmp;
    				}
    				if(xx<(rc-1)){
    					tmp=tmp+" ";
    				}
    				tmp2=tmp2+tmp;
    			}
    			if(tmp2.CompareNoCase(cmd_return_soll_1)==0){
    				ret=TRUE;
    				CString meldung;
    				meldung.Format("Kein Fehler: %s",tmp2);
    				AfxMessageBox(meldung);
    
    			}else{
    				CString meldung;
    				meldung.Format("Fehler: %s",tmp2);
    				AfxMessageBox(meldung);
    			}
    		}
    		delete[] recvbuffer;
    		delete[] buf;
    	}
    
    	if(cmd.CompareNoCase("BLUHM_ISPRINT")==0){
    		int len=0;
    		CString cmd="";
    		CString cmd_return="";
    		// <STX>1Ok<ETX>
    		CString cmd_return_soll="02 31 4F 4B 03";
    		CString tmp="", tmp2="";
    
    		struct timeval tv;
    		tv.tv_sec = 1;
    		tv.tv_usec = 0;
    
    		char *recvbuffer=NULL;
    		rc=select(1,&fdSet,NULL,NULL, &tv); 
    	    if(rc==SOCKET_ERROR) {
    			CString ausg;
    			ausg.Format("Fehler: select, fehler code: %i \n",WSAGetLastError());
    			AfxMessageBox(ausg);
    		}else{
    
    			CString ausg;
    			ausg.Format("%i",rc);
    			AfxMessageBox("ausg:"+ausg);
    
    			recvbuffer = new char[1024];
    			rc=recv(s,recvbuffer,1024,0);
    
    			if(rc==SOCKET_ERROR) {
    				CString str;
    				str.Format("%d",WSAGetLastError());
    				AfxMessageBox("Fehler: recvfrom, fehler code: "+str);
    			} else {
    				recvbuffer[rc]='\0';
    
    				for(int xx=0; xx<rc; xx++){
    					tmp.Format("%x", recvbuffer[xx]);
    					if(tmp.GetLength()<2){
    						tmp="0"+tmp;
    					}
    					if(xx<(rc-1)){
    						tmp=tmp+" ";
    					}
    					tmp2=tmp2+tmp;
    				}
    				//AfxMessageBox(tmp2);
    				if(tmp2.CompareNoCase(cmd_return_soll)==0){
    					ret=TRUE;
    					CString meldung;
    					meldung.Format("Kein Fehler: %s",tmp2);
    					AfxMessageBox(meldung);
    				}else{
    					CString meldung;
    					meldung.Format("Fehler: %s",tmp2);
    					AfxMessageBox(meldung);
    				}
    			}
    		}
    		delete[] recvbuffer;
    	}
    
    	/////////////Befehle Ende////////////////
    
    	/////////////Disconnect Anfang////////////////
    	closesocket(s);
    	WSACleanup();
    	/////////////Disconnect Ende////////////////
    	inUse = false;
    	return ret;
    }
    

    mfg LT



  • rc=select(1,&fdSet,NULL,NULL, &tv);
    

    versuchs mal mit rc = select(1, &fdSer, NULL,NULL, tv);

    Gruss IchBinNichtSicher



  • versuchs mal mit rc = select(1, &fdSer, NULL,NULL, tv);

    ^^ was soll das bringen ? fdSer gibts bei mir net als variable und tv ohne & bringt fehelrmeldung



  • Also vorneweg ich hab mich jetzt nicht durch deinen Code gequält, aber ein paar Punkte zum Ablauf.
    Du kannst drei Filedeskriptoren-Sets (read/write/exception) an select() übergeben und ein Timeout. Bevor du select() aufrufts, musst du die gewünschten Sockets in das Set schreiben, evtl. vorher alles löschen. Wenn select() zurück kommt, dann ist entweder ein timeout aufgetreten, ein Fehler oder ein Socket-Ereignis. Das Socket-Ereignis ist dann im jeweiligen Set gesetzt, also der Socket. Das musst du überprüfen. Sprich wenn kein Ereignis auftritt ist das Set leer, auch wenn du vorher einen Socket eingetragen hast.



  • Error 10038:
    WSAENOTSOCK One of the descriptor sets contains an entry which is not a socket.



  • ok frage zu deinem geschriebenen:

    reihnfolge bei mir siet wie folgt aus:

    -> Connect
    -> FD_SET(soc,&fdSet);
    -> FD_ZERO(&fdset)
    -> Befehl: ON an Drucker (Bluhm_ON)
    -> Disconnect

    -> Connect
    -> FD_SET(soc,&fdSet);
    -> Befehl: SET_VTEXT an Drucker (Bluhm_SET_VTEXT) mit entsprechenden Parameter
    -> Disconnect

    -> Connect
    -> FD_SET(soc,&fdSet);
    -> Befehl: IsPrint an Drucker (Bluhm_ISPRINT)
    -> rc=select(1,&fdSet,NULL,NULL, &tv);
    -> <-- hier kommt fehlermeldung 10038 (Objekt sei kein socket)
    -> Disconnect

    ^^ wieso kommt da das fdset kein socket sei oder was versteh ich da falsch?



  • LordTerra schrieb:

    ok frage zu deinem geschriebenen:

    reihnfolge bei mir siet wie folgt aus:

    -> Connect
    -> FD_SET(soc,&fdSet);
    -> FD_ZERO(&fdset)
    -> Befehl: ON an Drucker (Bluhm_ON)
    -> Disconnect

    -> Connect
    -> FD_SET(soc,&fdSet);
    -> Befehl: SET_VTEXT an Drucker (Bluhm_SET_VTEXT) mit entsprechenden Parameter
    -> Disconnect

    -> Connect
    -> FD_SET(soc,&fdSet);
    -> Befehl: IsPrint an Drucker (Bluhm_ISPRINT)
    -> rc=select(1,&fdSet,NULL,NULL, &tv);
    -> <-- hier kommt fehlermeldung 10038 (Objekt sei kein socket)
    -> Disconnect

    ^^ wieso kommt da das fdset kein socket sei oder was versteh ich da falsch?

    FD_SET(s,&fdSet);
    
        if(cmd.CompareNoCase("BLUHM_ON")==0){
            int len=0;
            CString cmd="";
            CString cmd_return="";
            //Ok<CR>
            CString cmd_return_soll="4F 6B 0D";
    
            FD_ZERO(&fdSet); // Inhalt leeren
    

    Du fügst den Socket der verbindungen annimmt zu, fdSet hinzu und leerst den Inhalt ein paar Zeilen wieder.

    Gruss IchBinNichtSicher



  • hmmm jo mach ich weil ich gelesen hab das man das machen muss ...

    also laut der webseite (sorry link net mehr da) hies es :
    - man soll den socket aufmachen
    - dann den fdset
    - dann fdzero <--- nur beim 1. mal

    daher hab ich das fdzero dort hingeschrieben wo ich das zwar 1 mal ausführe aber vor dem setvtext und vor isprint



  • LordTerra schrieb:

    hmmm jo mach ich weil ich gelesen hab das man das machen muss ...

    also laut der webseite (sorry link net mehr da) hies es :
    - man soll den socket aufmachen
    - dann den fdset
    - dann fdzero <--- nur beim 1. mal

    daher hab ich das fdzero dort hingeschrieben wo ich das zwar 1 mal ausführe aber vor dem setvtext und vor isprint

    fdzero must du vor fdset hinschreiben.

    Gruss IchBinNichtSicher



  • Ein fd_set ist nichts weiter, wie eine Datenstruktur, wo du Sockets eintragen kannst. FD_ZERO rufts du nur auf, um sicher zu stellen, dass das fd_set leer ist. Das fd_set selber macht gar nichts. Damit damit etwas geschieht, musst du es an select() übergeben, oder eine andere Funktion, die damit arbeiten kann.
    Eigentlich ist das auch in der MSDN recht umfangreich und ausführlich beschrieben.

    http://msdn.microsoft.com/en-us/library/ms740141(VS.85).aspx



  • Nick Unbekannt schrieb:

    Ein fd_set ist nichts weiter, wie eine Datenstruktur, wo du Sockets eintragen kannst. FD_ZERO rufts du nur auf, um sicher zu stellen, dass das fd_set leer ist. Das fd_set selber macht gar nichts. Damit damit etwas geschieht, musst du es an select() übergeben, oder eine andere Funktion, die damit arbeiten kann.
    Eigentlich ist das auch in der MSDN recht umfangreich und ausführlich beschrieben.

    http://msdn.microsoft.com/en-us/library/ms740141(VS.85).aspx

    So wie ich immer gedacht habe löscht FD_ZERO den Inhalt von fd_set, und das hat er getan nachdem er FD_SET aufruft.

    Er übergibt fd_set leer an select().
    Möglicherweise kommt daher die Fehlermeldung 10038 (Objekt ist kein socket).

    Gruss IchBinNichtSicherr



  • ok wenn ich das zero vor den set mache bekomm ich immer nur "0" als rückgabewert ... egal wie ich es mache ...



  • IchBinNichtSicher schrieb:

    Nick Unbekannt schrieb:

    Ein fd_set ist nichts weiter, wie eine Datenstruktur, wo du Sockets eintragen kannst. FD_ZERO rufts du nur auf, um sicher zu stellen, dass das fd_set leer ist. Das fd_set selber macht gar nichts. Damit damit etwas geschieht, musst du es an select() übergeben, oder eine andere Funktion, die damit arbeiten kann.
    Eigentlich ist das auch in der MSDN recht umfangreich und ausführlich beschrieben.

    http://msdn.microsoft.com/en-us/library/ms740141(VS.85).aspx

    So wie ich immer gedacht habe löscht FD_ZERO den Inhalt von fd_set, und das hat er getan nachdem er FD_SET aufruft.

    Er übergibt fd_set leer an select().
    Möglicherweise kommt daher die Fehlermeldung 10038 (Objekt ist kein socket).

    Gruss IchBinNichtSicherr

    ^^ das problem hierbei ist aber :

    ich rufe das conntect mehrfach auf !!!

    also ich connecte mich führe nen start des druckers aus und disconnecte mich wieder...

    dann concete ich mich um ein set text auszuführen (dieses liefert 2 rückgaben auf recv)

    ich warte die 1. ab und disconnecte mich wieder

    dann conntecte ich mich neu und warte auf das 2. recv

    und ich glaube das geht nicht ... aber da bin ich mir net sicher -.-

    mfg LT



  • IchBinNichtSicher schrieb:

    So wie ich immer gedacht habe löscht FD_ZERO den Inhalt von fd_set,

    Das ist auch richtig so. Ich habe auch nicht auf deinen Beitrag geantwortet. Mir ist nur aufgefallen, dass er im gleichen Kontext die Makros ohne select() benutzt und das ist Unsinn.

    IchBinNichtSicher schrieb:

    Er übergibt fd_set leer an select().
    Möglicherweise kommt daher die Fehlermeldung 10038 (Objekt ist kein socket).

    Eigentlich und da bin ich mir nicht sicher, dürfte er die Fehlermeldung nur bringen, wenn du versuchst einen Nicht-Socket in der Datenstruktur abzulegen. Ob man bei select() zwangsläufig mindestens einen Socket angeben muss weiß ich nicht, aber man kann über das Timeout eine Pause realisieren, welche auch ohne Socket nützlich sein kann.



  • Sich mehrmals zu verbinden ist prinzipiell auch kein Problem. Wobei ich nicht verstehe, warum du die Verbindung beenden musst? Solange dein Druckauftrag läuft kann uns soll sich niemand anders mit dem Drucker verbinden. Wenn du die Verbindung blockierst erhältst du also auch mehr Sicherheit. Ich würde aber mal deinen Code stark überdenken und in kleine Funktionen/Methoden aufteilen. So wie er jetzt da steht, ist er sehr schwer zu lesen und zu verstehen. Damit erhöhst du nur unnötig das Fehlerrisiko. Die Verbindung offen zu lassen würde aber vieles einfacher machen, außer es gibt einen Grund dafür es nicht zu tun?



  • moin

    jo es hat schon nen sinn das ich mich immer nur für ein kommando mit dem drucker verbinde ... das tool was ich schreib is nen überwachungstool und es soll von verschiedenen stellen möglich sein den drucker zu überwachen ... daher muss ich das so programmieren ...

    zum thema unleserlichkeit ... hmmm ganz ehrlich ich dachte eigentlich das ich es eben schon gut gekapselt hab ... was soll ich denn deiner meinung nach noch auslagern ???

    mfg lt



  • Da musst du selber mal drüber schauen, was man zusammen fassen kann oder evtl. sogar wiederverwenden. Vielleicht muss man auch Sachen allgemeiner formulieren, damit sie öfters angewandt werden können. Verringert aber trotzdem die Möglichkeiten von Fehlern enorm. Zuviel sollte man natürlich auch nicht zusammenfassen, nicht dass die Fallunterscheidungen überhand nehmen. Wenn du meinst es ist gut gegliedert und es kann auch nichts mehr zusammengefasst werden, dann kann du immer noch die einzelnen Schritte in Funktionen packen und in deiner Funktion aufrufen.
    Das ist aber nur ein Vorschlag, ich will dir nicht vorschreiben, wie du deine Programme zu schreiben hast. Was für dich sicher auch noch interessant sein könnte ist das Stichwort Objektorientierung.
    Wenn du dir ein Objekt Drucker anlegst, dann kannst du dort im Konstruktor deine Initialisierung vornehmen und den Destruktor alles wieder aufräumen lassen. Heißt du musst dich nicht mehr selber darum kümmern. Dem Objekt verpasst du dann noch eine Methode zum Senden, welche kurzfristig die Verbindung herstellt und vielleicht eine zum Lesen. Ich kenne jetzt aber dein Anforderungsprofil auch nicht.
    Durch einen übersichtlicheren Quelltext hättest du mich zum Beispiel auch dazu animieren können, ihn einmal zu lesen. Um zu verstehen was du wirklich machen willst. Wenn ich erst ewig lange grübeln muss, dann hab ich dazu keine Lust mehr. Wobei ich es auch gar nicht erst versucht habe, weil du mich vorher schon abgeschreckt hast. So kompliziert muss also dein Ablauf gar nicht sein.



  • hmmm mag sein das es auch einfacher geht ...

    aber naja so schwierig find ich meinen quellcode gar net ...
    erst kommt n bissi was zur socket-verbindung
    dann kommen die befehle die in senden und empfangen aufgegliedert sind
    und dann kommt n bissi dicsonncet kram also find den code nu net so unübersichtlich ... aber is sicher ansichtssache 🙂

    aber problem besteht immer noch ...
    also im mom hab ich das fd_zero vor den fd_set gesetzt
    (wohlgemerkt bei jeder komunikation)

    ergebnis= ich bekomm immer ne 0 als returnwert von select()

    is also auch net das was ich will ...



  • Hallo

    Zum einen, wenn 0 zurückkommt bedeutet das nur das dein Timeout von 1 sec abgelaufen ist und mehr nicht. Also entweder erhöst du deinen Timeout oder du musst die Methode mehrfach in einer Schleife aufrufen. So in etwas (Vorsicht nur PseudoCode):

    while (empfangen) {
      FD_ZERO(fdset);
      FD_SET(socket, &fdset);
      ret = select(0, &fdset, null, null, &tv);
      if (0 < ret) {
        if (FD_ISSET(socket, &fdset)) {
          // es kamm was an
          ret = recv(....)
          if (SOCKET_ERROR != ret) {
            // Daten auswerten
          }
          else {
            // Die Verbindung wurde getrennt
          }
          empfangen = true;
        }
      }
    } // while (....
    

    Nur so nebenbei, select ist ausgelegt um auf mehrere Sockets gleichzeitig zu hören, du könntest auch jederzeit denn Socket entsprechend umstellen das er Asynchron läuft, dann musst du die Wartezeit zwischen den Aufrufen nur selber mit Sleep einbauen. Aber um die While-Schleife wirst nicht rumkommen.

    MfG Marco



  • danke dir marco ...

    die schleife hatte ich eh vor zu benutzen

    mein programm ruft ja den cmdserver auf ...

    so nach dem motto:

    CString cmd="BLUHM_ON";
    if(cmdServer(cmd, ip , port)){
    
      cmd="BLUHM_SET_VTEXT";
      if(cmdServer(cmd, ip , port)){
    
        do{
          cmd="BLUHM_ISPRINT";
          if(cmdServer(cmd, ip , port)){
            AfxMessageBox("Hat gedruckt mach noch was");
          }
        }while("bis ich sage stop");
      }
    }
    

    mfg kala


Log in to reply