wirre zeichen :(

T

tobsucht

Grünschnabel
hallo,
ich arbeite zur zeit an einem simplen IRC-chatprogramm in C++, bestehend aus einem client und einem server. mein problem ist, dass ich nicht in der lage bin nachrichten vom server zu empfangen bzw. zu parsen, damit der header wegfällt und z.b. noch ein "You have joined the channel Fußball" kommt, wenn man /join Fußball am client eingibt. ?(

ich habe als erste sprache java gelernt und muss jetzt in C++ für die uni was proggen, abgabe ist am montag :( :hilfe2:

ich empfange nur wirre zeichen vom server und hab keine ahnung woran das liegt. mein auto-login, eine simple nachricht an den server funzt auch irgendwie nicht, deshalb ist der auskommentiert..

ich poste hier mal eine kurzform des quellcodes von meinem client.
beim senden habe ich leider auch noch das ein oder andere problem. ich denke mal die hauptursache liegt darin, dass ich keine ahnung von strings und chars und die umwandlung zwischen beiden habe. (stichwort nullterminator etc.).

wäre nett falls sich hier der ein oder andere experte der sache annehmen könnte, denn ich denke das die meisten fehler in meinem code auf dem selben problem beruhen.

danke im vorraus,
tobsucht

Code:
#include "client.h"

using namespace std;
	    
		
client::client(string hostname, string port, string nickname)  {

	this-> hostname = hostname;
	this-> port = port;
	this->nickname= nickname;
	topic="";
	
	startClient(hostname, port);

}



int client::startClient(string hostname, string port)  {


const char *host; 
const char *service; 
service = port.c_str();
host = hostname.c_str(); 

int error; 
struct addrinfo hints; 
struct addrinfo *addr0; 

memset(&hints, 0, sizeof(hints)); 
//hints.ai_family = PF_UNSPEC;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; 
hints.ai_protocol = IPPROTO_TCP; 
hints.ai_flags = 0; 


printf("Looking up host.."); 

	if ((error = getaddrinfo(host, service, &hints, &addr0)) < 0) { 
		perror(gai_strerror(error)); 
		return 1; 
	} 

printf("  OK \n");
int sockno; 
struct addrinfo *addr; 

for (addr = addr0; addr; addr = addr->ai_next) { 
	
	printf("Creating socket (ai_family=%d, ai_socktype=%d, ai_protocol=%d)...\n", 
	addr->ai_family, 
	addr->ai_socktype, 
	addr->ai_protocol
	); 
	
	if ((sockno = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)) < 0) { 
		perror("socket"); 
		continue; 
	}
	printf("  OK \n");
	printf("Connecting to host..."); 
	if ((connect(sockno, addr->ai_addr, addr->ai_addrlen)) < 0) { 
		perror("connect"); 
		close(sockno); 
		continue; 
	} 
	break; 
} 
if (!addr) { 
	printf("No connection found\n"); 
	return 1;
}
printf("  OK \n");
 
freeaddrinfo(addr0); 


bool first_login = true;
 std::string input;
 std::string cmd;
 
fd_set read_set0;

FD_ZERO(&read_set0);
FD_SET(STDIN_FILENO, &read_set0);
FD_SET(sockno, &read_set0);

	do { 
		char buffer[1024];
		int res;
		ssize_t length; 
		//int length;
		fd_set read_set = read_set0; 
		if ((res = select(sockno + 1, &read_set, NULL, NULL, NULL)) > 0) { 
							
			/*	
				// für auto-login, geht noch nicht.
				if (first_login==true)  {
						string logincmd = "/LOGIN ";
						cmd = getCommand(logincmd).c_str();
						cout<<"getCommand liefert: "<<cmd<<endl;
						strcpy(buffer, cmd.c_str());
						first_login = false;
				}
				else { */
		
					if (FD_ISSET(STDIN_FILENO, &read_set)) { 
					printf("Read STDIN...\n");

						if ((length = read(STDIN_FILENO, buffer, sizeof(buffer))) < 0) {
							perror("read"); 
							continue;
						}					
					//input = buffer;
					cmd = getCommand(buffer).c_str();
					cout<<"cmd: "<<cmd<<endl;
					strcpy( buffer, cmd.c_str());
					cout<<"buffer: "<<buffer<<endl;
					buffer[length]='\0';
					//strcpy( buffer, input.c_str());
				}
	
				printf("Write socket...\n");
				buffer[length]='\0';
				if ((length = write(sockno, buffer, length)) < 0) { 
						perror("write");
						continue;
					}
				//} 

	
		if (FD_ISSET(sockno, &read_set)) { 
			printf("Read socket...\n"); 
			
			if ((length = read(sockno, buffer, sizeof(buffer))) < 0) { 
				perror("read"); 
				continue;
			cout<<"length: "<<length<<endl;
			} 
			else if (length == 0) { 
				printf("Server closed connection\n"); 
				break;
			} 
			printf("Write STDOUT...\n");
			if ((length = write(STDOUT_FILENO, buffer, length)) < 0) { 
				perror("write");
				continue;
			}
			
		buffer[length]='\0';
		std::string tmp = buffer;
		cout<<handleServerMessage(tmp)<<endl;	
		//cout<<"inc_buffer: "<<buffer<<endl;			
		}
		} 
	else if (res < 0 && errno == EINTR) { 
		continue;
	} 
	else { 
		perror("select"); 
		return 1;
	}
	}
		while (1); 
		close(sockno); 
	return 0;
}


std::string client::getCommand(string message)  {
	
	int msg_length = message.find(' ', 0);
	std::string command = message.substr(0, msg_length);
	int channel_msg_length = message.find('/', 0);
	std::string oldname;
	std::string oldtopic;
	std::string cmd_code;

   
	
	
	if ((command == "/JOIN" || command == "/join") && message.size() > 6) {
        channel = message.substr(msg_length+1, MAXCHANNELNAME);
           	cout<<"You are in channel "<<channel<<'.'<<endl<<flush;
			cmd_code ="10101";   
			cmd_code+=channel;
			return cmd_code;
	}
    

	else if (((command == "/LOGIN") || (command == "/login")) && message.size() > 6) {	
			cmd_code ="10001";
			cout<<nickname<<endl;
			cmd_code+=nickname;
			cout<<cmd_code<<endl;
			return cmd_code;
	}
			else {		
				cmd_code ="10011";
				cmd_code+=topic;
				cout<<cmd_code<<endl;
				return cmd_code;
			}
	}
	
    else if ((command == "/PRIVMSG" || command == "/privmsg")  && message.size() > 10)  {
			string buf1, buf2;
			buf1 = message.substr(msg_length+1, message.find(' ', msg_length+1)-msg_length-1);
			buf2 = message.substr(message.find(' ', msg_length+1)+1, message.size()-message.find(' ', msg_length+1)-1);
			cmd_code="11011";
			cmd_code+=buf1; // muss noch mit server synchronisiert werden
			cmd_code+=buf2;
			return	cmd_code;
		
	}
	
	
    else if ((command == "/QUIT" || command == "/quit") && message.size() == 5) {
			cmd_code+="10010";
			return cmd_code;
    }
	
	else if((channel_msg_length==-1)) {
			cmd_code="10111";
			cmd_code+=message;
			return cmd_code;
	}



}



std::string client::handleServerMessage(string message)  {

std::string header=message.substr(0, 5);
int server_msg_length = message.length();
std::string modified_msg;
	
	if (header == "10111")  {
		modified_msg = message.substr(5, server_msg_length);
		return modified_msg;
	}
	else if (header == "10101") {
		std::string temp = ("You are in channel ");
		temp += modified_msg;
		temp += '.';
		return temp;
	}
}
 
if (header == "10111")
Sowas macht wahrscheinlich nicht das, was du denkst.

Strings sind (zumindest in C..) einfach arrays vom Typ char, die (meistens) mit einem null-char ('\0' oder int-Wert 0) terminiert werden. (Mit C++ String-Objekten kenn ich mich nicht aus..)
Was du da vergleichst, sollten die Anfangsaddresse der beiden Strings (ie nulterminierten char-Arrays) sein.

Code:
#include <stdio.h>
#include <stdlib.h>


int main(void) {
    char *foo = "hello";
    if (foo == "hello") {
        printf("foo address:     %p\n\"hello\" address: %p\n\n", foo, "hello");
    }
    char bar[6];
    bar[0] = 'h';
    bar[1] = 'e';
    bar[2] = 'l';
    bar[3] = 'l';
    bar[4] = 'o';
    bar[5] = '\0';
    if (bar == "hello") {
        printf("This shall never execute\n");
    }
    else {
        printf("bar as string:     \"%s\"   address: %p\n", bar, bar);
        printf("\"hello\" as string: \"%s\"   address: %p\n", "hello", "hello");
    }
    return 0;
}
 
if (header == "10111")

Sowas macht wahrscheinlich nicht das, was du denkst.

doch tut es, wenn ich die handleServerMessage-Methode auskommentiere und /login eingebe funktioniert es. an diesem vergleich sollte es nich liegen.
.
.
.
EDIT (autom. Beitragszusammenführung) :
.

brauche ich vielleicht einen char variabler länge damit ich die nachrichten alle terminieren kann bevor nachdem read() drübergelaufen is und bevor
Code:
write(sockno, buffer, sizeof(buffer))
beginnt?

wenn ja, wie würdest du das am sinnvollsten anstellen? bislang empfängt der server nur nachrichten, die so aussehen:

10001to???

wobei 10001 der header für login ist, anschliessend sollte da tobi stehen und stattdessen bekomme ich 3 solcher komischen fragezeichen ausgegeben, also nicht das fragezeichen-symbol sondern eher eins, als könne meine konsole nix mit den zeichen anfangen..
 
Zuletzt bearbeitet:
Ich muss zugeben, dass ich bis jetzt nur mit C erfahrung gemacht hab und da ist das bearbeiten von strings etwas anders. Bist du dir sicher, dass
Code:
			cmd_code ="10101";
das tut was es tun soll?

Im übrigen wüsste ich gern von wo du den ursprünglichen source hast, normalerweise mischt man printf und cout nicht. Im übrigen sind die dafür vorgesehenen includes gar nicht drinnen.

Ich hab ehrlichgesagt nicht viel ahnung was das ganze programm machen sollte, aber ohne mit dem debugger drüberfahren zu können ist alles, was ich sagen kann schlichtweg geraten. Und so viel hab ich vom ++ auch nicht abbekommen, das mir da was direkt ins Auge springen würde.
 
Hi,

konkret mit dem Socket Problem kann ich auch nicht wirklich helfen, da ich Socket Programmierung unter C++ noch nie gemacht habe. Auch mit std::string habe ich noch nie gearbeitet.

Beim ueberfliegen sind mir nur eine ganze Reihe von Unregelmaessigkeiten aufgefallen.
Wie marcellus schon schrieb, vermischt du printf und cout die ganze Zeit, das wird im Allgemeinen als schlechter Stil empfunden. Ausserdem benutzt du den Namensraum std, schreibst den Namensraum aber bei Strings trotzdem immer explizit dazu. Auch da wuerde ich sagen, entscheide dich fuer eins von beiden, entweder du benutzt "using namespace std" oder nicht. Ich persoenlich habe es lieber explizit.

Aber am schlimmsten ist die Formatierung von dem Code, vollkommen inkonsistent. Ich persoenlich weigere mich mir Code naeher anzugucken der nicht mal konsistent formatiert ist.

Bei C++ Klassen kommt die moegliche Benutzung stark darauf an welche Operatoren ueberladen wurden. Laut dieser Referenz, http://www.cppreference.com/wiki/string/string_operators, wurde der Zuweisungsoperator(=) so ueberladen dass eine Zuweisung von char* zu std::string funktioniert (z.B. std::string str = "foo"). Denn wenn ich mich richtig erinnere, wird in C und C++ eine Zeichenkette die mit "" definiert wurde, durch den Pointer auf das erste Element der Zeichenkette ersetzt, und gleichzeitig korrekt mit dem Nullterminator abgeschlossen. D.h.
Code:
char * szFoo = "foo"
reserviert 4 Byte im Speicher fuer die Zeichenkette 'foo\0', und liefert den Zeiger auf 'f' zurueck.

Was allerdings nicht in der Referenz steht, ist der Fall den Gott_in_schwarz angesprochen hat. Der Gleichheitsoperator(==) wurde scheinbar nur fuer zwei string Klassen ueberladen, aber nicht fuer string Klassen und char Pointer. Und "foo" liefert wie weiter oben beschrieben einen char Pointer auf 'f' zurueck. Ergo muesste es wahrscheinlich eher
Code:
if (header.compare("10111") == 0)
heissen. Wie gesagt, selber nie getestet, aber das entnehme ich der Referenz.

@marcellus
Er schrieb dass es nur ein Auszug ist, das duerfte der Grund dafuer sein, dass die entsprechenden includes nicht da sind.

mfg,
bytepool
 
Wenn du sowas postest mach dir doch bitte wenigstens die mühe das etwas leslicher zu formatieren.
Da bekommt man doch kopfschmerzen von und es ist mit Vim in 5 Tastenschlägen erledigt:
In vim: gg=G<enter>

http://rafb.net/p/alBVif16.html


1. Also erstmal "10111" ist ja wohl ganz großes Pfui.
Da weiß keiner was das sein soll, anscheinend nicht mal du!

Und es wird auch NICHT das tun, was es soll, Punkt. Siehe 3a.

2. Interessant wäre was für "wirre zeichen" du den überhaupt bekommst...

3a. Hast du dir überhaupt schon das Protokoll IRC angeschaut?
Hier die beste Anleitung die es gibt: http://www.faqs.org/rfcs/rfc1459.html ;)

3b. Hast du dir angeschaut wie strings bzw. zeichenketten in C++ implementiert werden und gehandhabt werden? std::string, char* char** usw.?
http://www.cplusplus.com/doc/tutorial/ntcs.html

C/++ ist zu recht kein Java, auch wenn die Syntax die gleiche ist, muss man etwas mehr "tieferes" Wissen mitbringen, also informier dich ;)
 
Hey,
erstmal Danke für eure Antworten. Ich werde das Ganze mit printf und cout heute abend korrigieren, genauso die auch Formatierung. Ich habe den Code zum Teil aus einem Beispiel übernommen und dieses nutzte printf, während ich selbst cout präferiere. Desweiteren war die Formatierung dieses Beispiels suboptimal und ich selbst habe bei Textedit für Ubuntu leider keine Autoformat bzw Beautify-Funktion gefunden. Vielleicht habt ihr ja den ein oder anderen Tip für mich womit so etwas am besten geht. Für emacs habe ich leider kein passendes Macro und mich auch noch nicht damit beschäftigen können eins selbst zu schreiben. Die von marcellus vorgeschlagene Methode zum Vergleichen von char* und string baue ich gleich mal ein und schreibe dann hier rein ob ich Erfolg hatte oder nicht...

Schönen Sonntag noch.
MfG
Tobsucht

edit:karru hat zeitgleich mit mir gepostet, ich nehme mir das mit VIM mal zu herzen. ich brauche keine anleitung für IRC, da wir ein eigenes protokoll mit eigenem header gebastelt haben. 10001 bedeutet dass sich ein user am server anmeldet. die darauf folgenden zeichen sollen dann der nickname sein. ich hatte gehofft, dass ich meine probleme mit gefährlichen halbwissen und ein paar tips aus dem forum hier in den griff bekomme, da mir die zeit davon läuft. das ganze ist eine aufgabe für ein praktikum, welches is morgen abgeben muss, also ist heute nachtschicht angesagt. die komischen zeichen die ich meine sind in der ubuntu-konsole fragezeichen mit schwarzem hintergrund. also nicht die standard-fragezeichen "?" sondern eher so etwas wie ein symbol für unbekannte zeichen.
 
Zuletzt bearbeitet:

Ähnliche Themen

Unix Webserver mit HTML Seite erstellen

String auf Konsole ausgeben

Zugriff Ubuntu 16.04. auf Freigabe 18.04. LTS nicht möglich

Crontab und Scripts - Problem

Port generieren, wenn nicht dann

Zurück
Oben