SocketServer Chat -> Probleme



  • Hallo, ich programmiere gerade einen Chat mit einem SocketServer und einem Client.
    Es funktioniert ansich ganz gut, ich kann eine verbindung aufbauen und mein client schickt einen text der dann angezeigt wird.
    Leider komme ich nicht dazu einen Text einzugeben.
    Ansich sollte er wenn ich nichts schicke if(chatclient->dataAvailable()) in die else Verzweigung. das macht er aber nicht, er geht ständig davon aus, dass ich Daten bereitstelle, was aber nicht geschieht.

    Hier der Quellcode zum Server:

    int main(void)
    {
    	string eingabe =" ";
    	string ausgabe = " ";
    	ServerSocket chatsrv(Port);
    	cout<<"Server started"<<endl;
    
    	while(true)
    	{
    		cout<<"Waiting for connection"<<endl;
    		Socket *chatclient = chatsrv.accept();
    		if(chatclient != NULL)
    		{
    			cout<<"connection established"<<endl;
    
    		}
    		while(eingabe != "exit" && ausgabe != "exit")
    		{
    			if(chatclient->dataAvailable())
    			{
    				ausgabe = chatclient->readLine();
    				cout<<"Partner < "<<ausgabe<<endl;
    			}
    			else
    			{
    				while (_kbhit())
    				{
    					getline(cin,eingabe);
    					chatclient->write(eingabe + '\n');
    				}
    			}
    		}
    	}
    
    }
    

    Falls ServerSocket.h und Socket.h benötigt werden stelle ich diese auch noch zur verfügung

    help plox"!



  • Wenn das Problem offensichtlich bei dataAvailable() liegt, solltest du die Funktion auch posten.
    (Und nur als Information: _kbhit() gehört weder zum C noch zum C++ Standard, aber das weißt du wahrscheinlich.)



  • *   (c) 2006 Michael Zimmer, HTS     
    int Socket::dataAvailable()
    {
      const int len = 1024;
      char b[len];
      return recv(socket, b, len, MSG_PEEK);
    }
    


  • Und wo prüfst du ob recv() überhaupt erfolg hat? Sonst probier doch mal select(), das scheint mir in dem Fall irgendwie sinnvoller..



  • kannst du mir die Methode umschreiben ?
    Ich habe die nicht programmiert sondern ein Professor an der TU Darmstadt.

    Ich bin auf einem techn. Gymnasium die Klassen wurden uns gegeben wir sollen damit arbeiten.



  • Hm.. dann poste doch noch bitte die beiden Header, dann kann ich das gleich testen.



  • ich poste einfach mal alles 🙂

    ServerSocketH

    //---------------------------------------------------------------------------
    #ifndef ServerSocketH
    #define ServerSocketH
    //---------------------------------------------------------------------------
    #include "Socket.h"
    
    class ServerSocket
    {
    private:
      int    port;
      SOCKET serverSocket;
    public:
      ServerSocket(int port);
      Socket* accept();
      void close();
    };
    #endif
    

    SocketH

    #ifndef SocketH
    #define SocketH
    
    #include <string>
    #include <winsock2.h>
    using namespace std;
    
    class Socket
    {
    private:
      string  host;
      int     port;
      SOCKET  socket;
    public:
      Socket(string host, int port);
      Socket(SOCKET socket);  // wird zur Socketerzeugung beim ServerSocket benoetigt
      bool connect();
      int  dataAvailable();
      void write(int b);
      void write(const char* b, int len);
      void write(string s);
      int  read();
      int  read(char* b, int len);
      string readLine();
      void close();
    };
    #endif
    

    Serversocket.cpp

    #include "ServerSocket.h"
    #include <iostream>
    //---------------------------------------------------------------------------
    //#pragma package(smart_init)
    
    ServerSocket::ServerSocket(int port)
    {
      this->port = port;
      // WinSock-DLL einbinden
      WSADATA wsa;
      WSAStartup(MAKEWORD(2,0),&wsa);
      // Server-Socket erzeugen
      this->serverSocket = ::socket(AF_INET, SOCK_STREAM, 0);
      if (this->serverSocket <= 0) {
        cerr << "Error: Socket\n";
        return;
      }
    
      // Erzeuge die Socketadresse des Servers
      SOCKADDR_IN myAddr;
      memset( &myAddr, 0, sizeof(SOCKADDR_IN));
      myAddr.sin_family = AF_INET;
      myAddr.sin_addr.s_addr = htonl(INADDR_ANY);
      myAddr.sin_port = htons((short)this->port);
    
      // Erzeuge die Bindung an die Serveradresse
      // (d.h. an einen bestimmten Port)
      if (bind(serverSocket, (SOCKADDR*)&myAddr, sizeof(SOCKADDR_IN)) == -1) {
        closesocket(serverSocket);
        cerr << "Error: bind\n";
        return;
      }
      // Teile dem Socket mit, dass Verbindungswunsch
      // eines Clients entgegengenommen wird
      if (listen(serverSocket, 5) == -1) {
        closesocket(serverSocket);
        cerr << "Error: listen\n";
        return;
      }
    }
    
    Socket* ServerSocket::accept()
    {
      // Bearbeite die Verbindungswunsch von Clients
      // Der Aufruf von accept() blockiert solange,
      // bis ein Client Verbindung aufnimmt
      SOCKADDR_IN remoteAddr;
      int len = sizeof(SOCKADDR_IN);
      SOCKET clientSocket = ::accept(serverSocket, (SOCKADDR*)&remoteAddr, &len);
      if (clientSocket > 0) {
        return new Socket(clientSocket);
      }
      return NULL;
    }
    
    void ServerSocket::close()
    {
      closesocket(serverSocket);
    }
    

    Socket.cpp

    /******************************************************************************
     *                                                                            *
     *   Klasse Socket                                                            *
     *                                                                            *
     *   Klasse zur Datenübertragung über die Socket Schnittstelle,               *
     *                                                                            *
     *   (c) 2006 Michael Zimmer, HTS                                             *
     *                                                                            *
     *   Borland C++Builder 4.0                                                   *
     *                                                                            *
     ****V1.0**********************************************************************/
    
    //---------------------------------------------------------------------------
    #include "Socket.h"
    //---------------------------------------------------------------------------
    
    Socket::Socket(string host, int port)
    {
      this->port = port;
      this->host = host;
      // WinSock-DLL einbinden
      WSADATA m_wsa;
      WSAStartup(MAKEWORD(2,0), &m_wsa);
      // Socket erzeugen
      this->socket = ::socket(AF_INET, SOCK_STREAM, 0);
    }
    
    Socket::Socket(SOCKET socket)
    {
       this->socket = socket;
    }
    
    bool Socket::connect()
    {
      SOCKADDR_IN addr;
      memset( &addr, 0, sizeof( SOCKADDR_IN ));
    
      addr.sin_family = AF_INET;
      addr.sin_port = htons((short)this->port);
      addr.sin_addr.s_addr = inet_addr(this->host.c_str());
    
      // Verbindung herstellen
      int rc = ::connect(socket, (SOCKADDR*) &addr, sizeof( SOCKADDR ));
    
      return rc != SOCKET_ERROR;
    }
    
    int Socket::dataAvailable()
    {
      const int len = 1024;
      char b[len];
      return recv(socket, b, len, MSG_PEEK);
    }
    
    void Socket::write(int b)
    {
      char tmp[1];
      tmp[0] = (char)b;
      send(socket, tmp, 1, 0);
    }
    
    void Socket::write(const char*b, int len)
    {
      send(socket, b, len, 0);
    }
    
    void Socket::write(string s)
    {
      send(socket, s.c_str(), (int)s.length(), 0);
    }
    
    int Socket::read()
    {
      char tmp[1];
      recv(socket, tmp, 1, 0);
      return tmp[0];
    }
    
    int Socket::read(char* b, int len)
    {
      return recv(socket, b, len, 0);
    }
    
    string Socket::readLine()
    {
      char buffIn[256];
      int pos = -1;
      do {
        pos++;
        recv(socket, buffIn+pos, 1, 0);
      } while (buffIn[pos] != '\n');
      buffIn[pos] = '\0';  // echo-String ist mit '\n' abgechlossen
      return string(buffIn);
    }
    
    void Socket::close()
    {
      closesocket(socket);
    }
    

    main

    #pragma comment(lib, "ws2_32.lib")
    #include <iostream>
    #include <conio.h>
    #include <stdio.h>
    #include <string>
    #include "ServerSocket.h"
    using namespace std;
    
    #define Port 55555
    
    int main(void)
    {
    	string eingabe =" ";
    	string ausgabe = " ";
    	ServerSocket chatsrv(Port);
    	cout<<"Server started"<<endl;
    
    	while(1)
    	{
    		cout<<"Waiting for connection"<<endl;
    		Socket *chatclient = chatsrv.accept();
    		if(chatclient != NULL)
    		{
    			cout<<"connection established"<<endl;
    
    		}
    		while(1)
    		{
    			if(chatclient->dataAvailable())
    			{
    				ausgabe = chatclient->readLine();
    				cout<<"Partner < "<<ausgabe<<endl;
    
    			}
    			else
    			{
    				while (_kbhit())
    				{
    					getline(cin,eingabe);
    					chatclient->write(eingabe + '\n');
    
    			}
    			}
    		}
    	}
    
    }
    


  • Oh man, den Code hat dein Professor geschrieben? Ich werde immer weiter desillusioniert hier, hilf mir doch bitte jemand.

    Ersetze in Socket.cpp die Funktion dataAvailable() durch

    int Socket::dataAvailable()
    {
      fd_set set;
      FD_ZERO(&set);
      FD_SET(this->socket, &set);
      timeval timeout;
      timeout.tv_sec = 0;
      timeout.tv_usec = 25;
      if (select(this->socket + 1, &set, 0, 0, &timeout) == -1)
        return 0; // error
      return FD_ISSET(this->socket, &set);
    }
    

    Und in main.cpp Zeile 37 while durch if.

    Das bleibt zwar extrem hässlich etwas unschön, aber es funktioniert und da dein Prof das ja so vorgegeben hat..



  • Hallo, vielen dank das hat nun wunderbar geklappt hab nun weiter gemacht und bekomme weitere fehler 😕
    Schon bei der Namensübergabe taucht ein unerwarteter Pufferfehler in dieser Zeile auf:
    " buffIn[pos] = '\0'; // echo-String ist mit '\n' abgechlossen"
    aus der Socket.cpp

    hier der server:

    int main(void)
    {
    	unsigned int Port;
    	time_t t;
    	string text = "";
    	string name_me = "Me";
    	string name_partner = "Opposite";
    	cout<<"Enter Portnumber ";
    	cin>>Port;
    	ServerSocket chatsrv(Port);
    	cout<<"Server started"<<endl;
    
    	while(1)
    	{
    		Sleep(1000);
    		system("cls");
    		cout<<"Waiting for connection, listening on Port "<<Port<<endl;
    		Socket *chatclient = chatsrv.accept();
    		if(chatclient != NULL)
    		{
    		cout<<"connection established"<<endl;
    		Sleep(1000);
    		system("cls");
    		cout << "============================================================"<<endl<<endl;
    		cout <<        "Socket Chat v1.0 - Please enter your name >";
    		cin>>name_me;
    		cout << endl;
    		cout << "============================================================"<<endl<<endl;
    		chatclient->write(name_me + "\n");
    		if ( chatclient->dataAvailable() )
    		{
    		name_partner = chatclient->readLine();
    		}
    		}
    		while(text != "Exit" && text != "exit" && text != "EXIT")
    		{
    			if(chatclient->dataAvailable())
    			{
    				text= chatclient->readLine();
    				time(&t);
    				cout << ctime(&t) <<name_partner<<" < " << text << endl;
    
    			}
    			else
    			{
    				while (_kbhit())
    				{
    					time(&t);
    					cout << ctime(&t) << name_me << " > ";
    					getline(cin,text);
    					if(text=="Ring" || text=="ring" || text=="RING")
    						{
    							chatclient->write("Sie haben ein Ring erhalten!\a\a\a\a\a\a\a\a\n");
    							cout<< name_me << " >"<<("Sie haben ein Ring gesendet!\a\a\a\a\a\a\a\a\n\n");
    						}
    
    						else
    							{
    							cout<<endl;
    							chatclient->write(text + "\n");
    							}
    			}
    			}
    		}
    		delete chatclient;
    	}
    

    und hier der client

    int main(void)
    {
    	cout<<"Enter IPnumber ";
    	getline(cin,IP);
    	cout<<endl<<"Enter Portnumber ";
    	cin>>Port;
    
    	Socket* CSocket = new Socket(IP, Port);
    
    	if (! CSocket->connect()) {
    		cout<< "Error: Connection failed!"<<endl;
    		return 1;
    	}
    	else 
    	{
    		cout<<"connection established"<<endl;
    		Sleep(1000);
    		system("cls");
    		cout << "============================================================"<<endl<<endl;
    		cout <<        "Socket Chat v1.0 - Please enter your name >";
    		cin>>name_me;
    		cout << endl;
    		cout << "============================================================"<<endl<<endl;
    		CSocket->write(name_me+"\n");
    		if ( CSocket->dataAvailable() )
    		{
    		name_partner = CSocket->readLine();
    		}
    		}
    		while(text != "Exit" && text != "exit" && text != "EXIT")
    		{
    			if(CSocket->dataAvailable())
    			{
    				text= CSocket->readLine();
    				time(&t);
    				cout << ctime(&t) <<name_partner<<" < " << text << endl;
    
    			}
    			else
    			{
    				while (_kbhit())
    				{
    					time(&t);
    					cout << ctime(&t) << name_me << " > ";
    					getline(cin,text);
    					if(text=="Ring" || text=="ring" || text=="RING")
    						{
    							CSocket->write("Sie haben ein Ring erhalten!\a\a\a\a\a\a\a\a\n");
    							cout<< name_me << " >"<<("Sie haben ein Ring gesendet!\a\a\a\a\a\a\a\a\n\n");
    						}
    
    						else
    							{
    							cout<<endl;
    							CSocket->write(text + "\n");
    							}
    			}
    			}
    
    	CSocket->close();
    	}
    
    	return 0;
    }
    

    bitte helf mir



  • Wenn die Verbindung geschlossen wird failt recv() und die Schleife läuft immer weiter, bis irgendwo zufällig ein '\n' gefunden wird. An der Stelle hast du dann aber natürlich keine Zugriffsrechte mehr und beim Versuch eine '\0' rein zu schreiben crasht es dann. Aber mal ehrlich: Das ist alles so schrecklich, ich kann dir da kaum weiter helfen. Guck dir den Stil deines Profs bloß nicht ab. In Zeile 8 z.B. - schreib einfach nur "Socket sock(Port, IP)", das new brauchst du so gut wie nie. Die Fehlerliste könnte man jetzt noch bis ins nächste Jahrhundert fortführen, aber lassen wir das. Wie gesagt, das gestellte Framework ist völlig unbrauchbar, damit kann man doch nicht arbeiten geschweige denn davon lernen.

    PS: Richtig und einheitlich einrücken solltest du dir angewöhnen. Hast du keine IDE die das für dich erledigt bzw. dich dabei unterstützt? Visual Studio 2010 wäre z.B. gratis, oder Eclipse, oder Code::Blocks.



  • das problem ist leider dass ich den chat mit diesem 'framework' programmieren muss, da ich sonst 0 Punkte für das Projekt bekomme 😕



  • Kannst du es nicht einfach komplett selbst schreiben?



  • nein leider habe ich was diese "tiefe" angeht keine ahnung.
    (Bin ja auf einem Gymi und studiere noch nicht..)

    also das mit dem \n ist so gedacht, dass ich eben jedesmal nach ein "\n" nachschicken muss:
    z.B chatclient->write(text + "\n");

    aber irgendwie gibt es eben dort ein fehler ?



  • edit: das seltsame ist, der client funktioniert er kommt nicht in diesen pufferüberlauf nur der server, irgendwo muss doch da der wurm drin stecken



  • Dev schrieb:

    (Bin ja auf einem Gymi und studiere noch nicht..)

    Das hindert einen doch nicht daran ein bisschen mit Sockets zu spielen. 😉

    Ein Dirty-Hack-Fix wäre:

    text = chatclient->readLine();
    if (text.length() == 0)
      break;
    

    Und bei read()

    if (recv(socket, buffIn+pos, 1, 0) <= 0)
      return "";
    

    Wie gesagt, das wird zwar irgendwann funktionieren, aber es bleibt einfach unglaublich hässlich. Wenn mein Lehrer mir das vorsetzen würde, würde ich streiken. (Oder gleich zum Gericht gehen, ich denke da kommt man mit Mobbing gut durch.)


Anmelden zum Antworten