select()

2fast4you87

Erfahrenes Mitglied
Hallo Leute,
Habe mit das tutorial von http://www.zotteljedi.de angeguckt und habe die Socket Programmierung jetzt unter Windows und Unix programmiert. Nun bin ich seit 2 Tagen schon dabei einen Server mit Select zu programmieren. Aber ich bekomme es einfach nicht hin! Ich weiß was Select macht und kann, nur wie ich es in meinem Code implementiere weiß ich nicht.

Ich habe einen Server der mit accept wartet bis eine Verbindung ankommt, danach blockiert er mit der fkt recv() so lange bis er eine antwort vom Client bekommt. Nur das möchte ich nicht. Er soll nicht Blockieren !

Hier mal mein Code ....
Code:
#include <windows.h>
#include <winsock.h>
#include <stdio.h>


	#pragma comment(lib,"wsock32.lib")

int startWinsock(void);

int main()
{

  timeval Timeout;
  Timeout.tv_sec = 5;
  Timeout.tv_usec = 0;
  fd_set fdSetRead;


  FD_ZERO(&fdSetRead);
  FD_SET(0,&fdSetRead);
  long rc;
  SOCKET acceptSocket;
  SOCKET connectedSocket;
  SOCKADDR_IN addr;
  char buf[256];


  rc=startWinsock();
  if(rc!=0){
    printf("Fehler: startWinsock, fehler code: %d\n",rc);
    return 1;
  }
  else
   printf("Winsock gestartet!\n");


  acceptSocket=socket(AF_INET,SOCK_STREAM,0);
  if(acceptSocket==INVALID_SOCKET){
    printf("Fehler: Der Socket konnte nicht erstellt werden, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
    printf("Socket erstellt!\n");

  memset(&addr,0,sizeof(SOCKADDR_IN));
  addr.sin_family=AF_INET;
  addr.sin_port=htons(22305);
  addr.sin_addr.s_addr=INADDR_ANY;
  rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));
  if(rc==SOCKET_ERROR){
    printf("Fehler: bind, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
    printf("Socket an port 22305 gebunden\n");

  rc=listen(acceptSocket,10);
  if(rc==SOCKET_ERROR){
    printf("Fehler: listen, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
    printf("acceptSocket ist im listen Modus....\n");

  connectedSocket=accept(acceptSocket,NULL,NULL);
  if(connectedSocket==INVALID_SOCKET){
    printf("Fehler: accept, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else{
    printf("Neue Verbindung wurde akzeptiert!\n");
  }

  
	select(1,&fdSetRead,NULL,NULL,&Timeout);
    int test = recv(connectedSocket,buf,sizeof(buf),0); 
	if(test > 0){
		printf("blaaaaa");
	}
	
    
  closesocket(acceptSocket);
  closesocket(connectedSocket);
  WSACleanup();
  return 0;
}



int startWinsock(void)
{
  WSADATA wsa;
  return WSAStartup(MAKEWORD(2,0),&wsa);
}

Zum Schluss noch ein paar Daten.
Ich Programmiere unter Windows (wie man sicherlich am Code erkennen kann.), Benutze Vc++ 6.

Ich hoffe ihr könnt mir weiter helfen .
 
select stellt nicht auf non-blocking um. Select prüft eine Liste von Sockets auf einen bestimmten Status. recv blockiert dann nach wie vor, es sei denn, du benutzt einen Socket, der von select als hat-Daten-empfangen markiert ist.
 
Du könntest natürlich für das recv(...) einen eigenen Thread aufmachen. Der wartet dann, während das Programm weiterläuft.
 
Hi die seite c-worker ist sehr gut, habe da den Server genommen!
Hab das ganze dann in vc++ 6 hinein implementiert, und es funktioniert auch alles, nur das er halt immer in der while(1) schleife hängt. Diese hat zur folge das die Grafik abschmiert aber der Server weiter läuft. Die Lösung wäre da den Server mit einem Thread laufen zu lassen, nur wie mache ich das in vc++ ?
Und meine 2 Frage ist, ich habe immer die Ausgabe in einem eingabefeld gemacht, das Problem ist aber das der kein \n verträgt...
Wollte dann ein Listenfeld dafür benutzen, nur wie bekomme ich einen Text in ein Listenfeld ?

Gruß 2fast4you ...

// EDIT, hätte vorher suchen müssen, jetzt weiß ich wie man was in ein Listenfeld reinschreibt ^^
 
Zuletzt bearbeitet:
Einen neuen Thread erzeugst Du mit CreateThread(...). Auch hierzu müßte es schon einige Beiträge im Forum geben.
 
Hallo,
ich habe mal einen kleinen Client in Vc++ 6 geschrieben.
Er connected auf den port 22305 und hat einen Thread der nacher das recv in einer while schleife laufen lassen soll. Später überwache ich das recv noch mit select().
Mein Problem ist jetzt aber folgendes :

Der Client Startet wunderbar, nur wie bekomme ich es hin das die variabel m_msg (das Listenfeld ) auch in der Thread funktion recvThread bekannt ist, sprich das ich in der Thread fkt sagen kann m_msg.AddString("Der Client schickt folgendes : client text .."); ?

Habt ihr da ne Ahnung, bin da echt am verzweifeln.

Gruß 2fast4you

Code:
int startWinsock(void)
{
  WSADATA wsa;
  return WSAStartup(MAKEWORD(2,0),&wsa);
}

  SOCKET s;
  SOCKADDR_IN addr;
  char buf[256];
  long rc;
  HANDLE hThread;
  DWORD dwThreadID;



DWORD WINAPI recvThread(LPVOID data){

 // hier soll recv rein und das er den inhalt von recv in das Listenfeld m_msg rein schreibt.

 return((DWORD)data);
}


void CClient_rcvDlg::OnOK() 
{


	hThread = CreateThread(NULL,
                                                    0,
                                                    recvThread,
                                                    (LPVOID)0,
                                                    0,
                                                    &dwThreadID); // Thread Starten
	rc=startWinsock();
		if(rc!=0)
			m_msg.AddString("Error   : startWinsock.");
		else
			m_msg.AddString("Running : startWinsock.");
	s=socket(AF_INET,SOCK_STREAM,0);
		if(s==INVALID_SOCKET)
			m_msg.AddString("Error   : socket()."); //Listenfeld
		else
			m_msg.AddString("Running : socket().");//Listenfeld

	memset(&addr,0,sizeof(SOCKADDR_IN)); 
	addr.sin_family=AF_INET;
	addr.sin_port=htons(22305); 
	addr.sin_addr.s_addr=inet_addr("127.0.0.1"); 

	rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
	if(rc==SOCKET_ERROR)
                                m_msg.AddString("Error   : connect gescheitert.");//Listenfeld
	else
		m_msg.AddString("Running : connect erfolgreich.");//Listenfeld
}

void CClient_rcvDlg::Ontrennen() 
{
  m_msg.AddString("Server wurde Beendet!");
  CloseHandle(hThread); // Thread beenden
  closesocket(s);
  WSACleanup();	
}


void CClient_rcvDlg::Onquit() 
{
  m_msg.AddString("Server wurde Beendet!");
  CloseHandle(hThread); // Thread beenden
  closesocket(s);
  WSACleanup();	
}
 
in der CreateThread-Methode kannst Du einen LPVOID-Zeiger angeben, der an die Threadfunktion übergeben wird. Der Aufruf wäre etwa so:
Code:
 hThread = CreateThread(NULL, 0, recvThread, (LPVOID)&m_msg, 0, &dwThreadID); // Thread Starten
In der threadfunktion sieht das dann so aus:
Code:
 DWORD WINAPI recvThread(LPVOID data){
    CListBox * pMsg = (CListBox *)data;
    
     // hier soll recv rein und das er den inhalt von recv in das Listenfeld m_msg rein schreibt.
    
     return((DWORD)data);
    }
wobei ich jetzt davon ausgehe, daß m_msg vom Typ CListBox ist.
Der Rückgabeweret einer Threadfunktion ist normalerweise 0, wen alles OK ist, oder eine Fehlernummer. Das ist wie der Rückgabewert einer main-Funktion, da das ja sozusagen die main-Funktion des Threads ist. Wenn sie beendet ist, dann ist der Thread beendet.
 
Hi,

hab das jetzt mal so gemacht, aber mein thread der funktioniert nicht so richtig! Das ganze läuft nicht paralel ... immer wenn ich den Thread Starte funktioniert wohl der Client, sprich er connectet wohl und der Server sagt auch wohl :" Neuer Client angenommen ". Aber die Grafik schmiert dann ab, weil die recv funktion blockiert, sogar mit einem Select... Hier mal der Code :

Code:
int startWinsock(void)
{
  WSADATA wsa;
  return WSAStartup(MAKEWORD(2,0),&wsa);
}

  SOCKET s;
  SOCKADDR_IN addr;
  char buf[256];
  long rc;
  HANDLE hThread;
  DWORD dwThreadID;
  FD_SET fdSet;
  timeval Timeout;




DWORD WINAPI recvThread(LPVOID data){

  Timeout.tv_sec = 0;
  Timeout.tv_usec = 100;
  CListBox * pMsg = (CListBox *)data;

  pMsg->AddString("Thread wurde gestartet");

	FD_ZERO(&fdSet);
	FD_SET(s,&fdSet);
	
while(rc != SOCKET_ERROR){
	rc=select(0,&fdSet,NULL,NULL,&Timeout);

		rc = recv(s,buf,sizeof(buf),0);
		pMsg->AddString(buf);
	}
}

 return((DWORD)data);

}


void CClient_rcvDlg::OnOK() 
{


	hThread = CreateThread(NULL,0,recvThread,(LPVOID)&m_msg,0,&dwThreadID);
	
	rc=startWinsock();
		if(rc!=0)
			m_msg.AddString("Error   : startWinsock.");
		else
			m_msg.AddString("Running : startWinsock.");
	s=socket(AF_INET,SOCK_STREAM,0);
		if(s==INVALID_SOCKET)
			m_msg.AddString("Error   : socket().");
		else
			m_msg.AddString("Running : socket().");

	memset(&addr,0,sizeof(SOCKADDR_IN)); 
	addr.sin_family=AF_INET;
	addr.sin_port=htons(22305); 
	addr.sin_addr.s_addr=inet_addr("127.0.0.1"); 

	rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
	if(rc==SOCKET_ERROR)
			m_msg.AddString("Error   : connect gescheitert.");
		else
			m_msg.AddString("Running : connect erfolgreich.");


		WaitForMultipleObjects(	1,	
								&hThread,
								TRUE,
								2000);//INFINITE wenn ich es auf unendlich stelle schmiert die grafik ab 
// nach den 2 sec kehrt der thread zurück und er liefert auch das recv ...

}


void CClient_rcvDlg::Onquit() 
{
  m_msg.AddString("Server wurde Beendet!");
  CloseHandle(hThread);
  closesocket(s);
  WSACleanup();	
}
 
Zurück