A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
Templates zijn op zich ook wel een handige uitkomst hier, maar gezien je geringe ervaring met C++ vraag ik me af of dat een handige suggestie is
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Uit het packetnummer halen we al uit wat voor een object het precies is, dat hoef ik niet nog een keer te maken in deze interface.
In principe doet dit dus hetzelfde als het object Object in Java, alleen maak je deze zelf met alle bovenliggende objecten,
@hierboven:
dat is ook niet hoe ik het bedoelde. ik heb mijn protocol al gespecificeerd, maar hoe ik dan al die verschillende soorten berichten in 1 class krijg. Inheritance is dan volgens mij de oplossing doordat je dan normaal kan casten naar de bovenliggende (of onderliggende als je het zo wilt zien) class. Dus het object fiets casten naar het object vervoersmiddel. En dan vervoersmiddel meesturen.
[ Voor 35% gewijzigd door k0ewl op 03-10-2006 16:34 ]
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
Nou wil hij dat alleen nog implementeren.Nu zijn we dus bezig gegaan en hebben een heel erg simpel protocol opgesteld. Namelijk dat we een pakketnummer hebben om te kijken wat het voor een soort pakket is en daar achter een dataveld van oneinding lang zodat we er een bestand in kunnen laden of zodat er voor een ACK pakketje één bitje mee kunnen sturen.
@k0ewl: Ik snap je probleem niet. In Java heb je idd een klasse Object en overerven alle andere klassen daar impliciet van. In C++ heb je dat niet, maar niets weerhoudt je er toch van om zelf een soort Object te definieren waar je alle overige klassen van laat afleiden
[ Voor 26% gewijzigd door .oisyn op 03-10-2006 16:34 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
juist... dat ben ik nu dus ook van plan....oisyn schreef op dinsdag 03 oktober 2006 @ 16:32:
@Soultaker: Z'n protocol is toch al beschreven?
[...]
Nou wil hij dat alleen nog implementeren.
@k0ewl: Ik snap je probleem niet. In Java heb je idd een klasse Object en overerven alle andere klassen daar impliciet van. In C++ heb je dat niet, maar niets weerhoudt je er toch van om zelf een soort Object te definieren waar je alle overige klassen van laat afleiden
Mijn kennis van C en C++ is ondertussen zover weggezakt dat ik dat even was vergeten.. krijg je ervan als je school je in 6 weken tijd C++ wilt leren en daarna 2 jaar er niets mee doet.
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
Maar goed, wat het casten betreft: je kunt enerzijds een eigen superklasse definiëren, of (als je een voldoende up-to-date compiler gebruikt) zorgen dat al je objecten een vtable hebben en dan gewoon dynamic_cast gebruiken. Waarschijnlijk is een superklasse sowieso wel nuttig, als je objecten gemeenschappelijke functionaliteit hebben.
Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein
Je praat over pakketten. Ik neem dus logischerwijs aan dat je UDP gebruikt (aangezien TCP een stream is en je door buffering niet kan uitgaan van pakketten ed). Dan heb je enerzijds de restrictie dat je UDP pakket een maximale grootte heeft afhankelijk van de MTU. En de restrictie dat encryptie op UDP pakketten een stuk moeilijker is aangezien je dus waarschijnlijk een "sessie" moet opbouwen en onderhouden.
Na deze kleine redenering denk ik dus dat je op TCP bezig bent wat een stuk logischer is met OpenSSL. Je "pakket" redenering met een pakket nummer en oneindige lengte is dus niet aan de orde. Als ik jouw was keek ik eens op TLV (Type, Length, Value).
Als je objecten wil serializen heb je in C++ wel enkele mogelijkheden. Je neemt een functie die je overload voor elk type die je wil verzenden, gebruikt templates of je laat elk object een interface (class met pure virtual functies) implementeren. (Dit zijn waarschijnlijk niet de enige methodes...)
ASSUME makes an ASS out of U and ME
De socket is ondertussen tot stand gekomen en we kunnen char arrays oversturen.
Nu heb ik een class Message gemaakt:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| #ifndef MESSAGE_H
#define MESSAGE_H
class Message {
protected:
unsigned int packet_type: 4;
public:
Message(int);
unsigned int get_packet_type(void);
};
Message::Message(int new_type) {
packet_type = new_type;
}
unsigned int Message::get_packet_type() {
return packet_type;
}
#endif |
En daarboven op heb ik met inheritance een class Message_ack gemaakt:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| #ifndef MESSAGEACK_H
#define MESSAGEACK_H
#include <iostream>
#include <Message.h>
using namespace std;
class Message_ack: public Message {
protected:
bool acknowledge;
public:
Message_ack(bool);
bool get_acknowledge(void);
};
Message_ack::Message_ack(bool ack):Message(1) {
acknowledge = ack;
}
bool Message_ack::get_acknowledge() {
return acknowledge;
}
#endif |
De andere classen volgen hetzelfde idee, maar net met andere functies en dergelijke.
Alleen ben ik nu nog bezig hoe ik object de stream in moet sturen ipv char arrays.
De functie send() heeft namelijk een const char* nodig en niet iets waar ik zo iets mee kan.
Even verder zoeken op google.
Edit:
Lijkt erop dat ik gewoon de size van het object moet bepalen en dan de pointer mee moet geven aan de send-functie met de lengte van het object.
Mhh, werkt niet. Ik moet een char array meegeven, anders gaat ie zeiken.
[ Voor 7% gewijzigd door k0ewl op 05-10-2006 21:06 ]
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
Maar wat nou als je object pointers naar andere objecten bevat? dat resulteert aan de andere kant van de lijn in een page fault en een dikke crash, omdat die pointer in het niets staat te wijzen.
Ikke niet helemaal snap jouw verhaal...__fred__ schreef op donderdag 05 oktober 2006 @ 21:19:
Als je specifiek je pointer naar je object cast naar een char * dan gaat dat wel werken. Als lengte kan je dan sizeof(T) gebruiken.
Maar wat nou als je object pointers naar andere objecten bevat? dat resulteert aan de andere kant van de lijn in een page fault en een dikke crash, omdat die pointer in het niets staat te wijzen.
Sorry, maar kan er echt weinig wijs uit worden door nogal kromme zinnen. (NOFI)
Misschien bedoel je dat als de pointer van message, niet naar een message wijst, maar naar een ander soort object?
Nou ik maak die message pas vlak voor het verzenden aan, dus gaat wel goed.
Edit: Krijg het pakketje aan de andere kant
[ Voor 18% gewijzigd door k0ewl op 05-10-2006 21:50 ]
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
Verder is een char een byte, een char* betekent dus gewoon een rijtje van bytes, en daarom verwacht de send functie een char*
[ Voor 13% gewijzigd door .oisyn op 05-10-2006 22:04 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.
Ik heb de hele nacht liggen programmeren en kom er nu niet meer uit.
het gaat natuurlijk om het socket gedeelte, dus dat stop ik hier ff in de code - tags.
Server:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| void Connection::start_server(int port) {
int valid;
if(open_socket()) {
socket_struct.sin_family = AF_INET;
socket_struct.sin_port = htons(port);
socket_struct.sin_addr.s_addr = inet_addr("0.0.0.0");
valid = bind(listen_socket, (SOCKADDR*)&socket_struct, sizeof(socket_struct));
if(valid == 0) {
valid = listen(listen_socket, SOMAXCONN);
if(valid == 0) {
answer_socket = SOCKET_ERROR;
while(answer_socket == SOCKET_ERROR){
answer_socket = accept(listen_socket, NULL, NULL);
connected = true;
}
}
}
}
}
bool Connection::open_socket() {
listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listen_socket == INVALID_SOCKET) return false;
} else return true;
} |
Client:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| void Connection::connect_server(int port, char *ip_address) {
int valid;
if(open_socket()) {
socket_struct.sin_family = AF_INET;
socket_struct.sin_port = htons(port);
socket_struct.sin_addr.s_addr = inet_addr(ip_address);
valid = connect(client_socket, (SOCKADDR*)&socket_struct, sizeof(socket_struct));
if(valid != 0){
cout << "Connection Error : " << GetLastError() << endl;
}
}
}
bool Connection::open_socket() {
client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(client_socket == INVALID_SOCKET) {
cout << "Invalid Socket : " << GetLastError() << endl;
return false;
} else return true;
} |
Ik maak gebruik van winsock. En die wordt in de constructors van de verschillende connection classes geinitialiseerd op de volgende manier:
1
2
| WSAData wData;
WSAStartup(MAKEWORD(2,2), &wData); |
Bij de server gaat het volgende wel goed:
- Ik maak de socket (success)
- ik bind de socket (success)
- luisteren op socket (success)
Het lijkt dus bij het accepten van de socket mis te gaan. En of dit nu aan de client of de server ligt, dat weet ik niet. Iemand een idee?
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
Een paar breakpoints zetten, steppen en je weet waar de fout zit.
Ducati: making mechanics out of riders since 1946
Dat heb ik ook gedaan.TheNameless schreef op vrijdag 06 oktober 2006 @ 12:20:
Dit is toch heel makkelijk te debuggen?
Een paar breakpoints zetten, steppen en je weet waar de fout zit.
en wel met deze: cout << "Connection Error : " << GetLastError() << endl;
Het leuke is dat deze 0 weergeeft. Dus dan zou het goed moeten zijn, maar waar hij dan connected niet gewoon op true zet, ik snap het gewoon even niet meer.
Als ik de server niet start, dan krijg ik de error dat het verbinden wel mislukt is met de volgende foutcode: 10061, welke staat voor: Connection Refused -- The target machine actively refused the attempt to connect to it.
Als ik de server wel start krijg ik die error niet, dus hij ziet de socket wel.
[ Voor 24% gewijzigd door k0ewl op 06-10-2006 12:29 ]
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
Volgens MSDN wel namelijk
De winsock library heeft namelijk een error gegenereerd en niet een thread van je applicatie.
[ Voor 39% gewijzigd door TheNameless op 06-10-2006 12:35 ]
Ducati: making mechanics out of riders since 1946
Structuur programma:
Volgens het MVC-model gemaakt. Dus een aparte communicator, controller en connection.
In connection wordt de variabele connected op true gezet.
Helaas was de functie in controller verkeerd en gaf die altijd false terug
Dat een keer veranderd naar return connection->is_connected(); en het werkt
Op naar het volgende probleem:
hoe zorg ik ervoor dat ik een buffer pak die groot genoeg is om het totale bericht in te laden
[ Voor 14% gewijzigd door k0ewl op 06-10-2006 13:11 ]
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
Kijk eens naar de MSG_PEEK optiek0ewl schreef op vrijdag 06 oktober 2006 @ 12:46:
Op naar het volgende probleem:
hoe zorg ik ervoor dat ik een buffer pak die groot genoeg is om het totale bericht in te laden
Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.
Als ik een bericht heb ontvangen, dan kan ik hem gewoon casten naar Message of Message_ack in dit geval. Dan kan ik de functie van Message aanroepen om te kijken welk soort pakket het is.
Dat gaat ook goed, maar daarna roep ik dus een functie get_acknowledge aan van de class Message_ack, maar dan krijg ik niets.
Ik mag hem dus wel casten etc, maar krijg niets terug
onderliggende functies:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| bool Connection::send_packet(Message *message, long size) {
int valid;
valid = send(client_socket, (char *)message, size, 0);
if(valid < size) {
printf("Send Error: %d\n\n", WSAGetLastError());
return false;
} else return true;
}
char* Connection::recieve() {
char buffer[BUFFERSIZE];
memset(buffer, '\0', BUFFERSIZE);
recv(client_socket, buffer, BUFFERSIZE - 1, 0);
return buffer;
} |
Het versturen:
1
2
| Message_ack *message = new Message_ack(true); connection->send_packet((Message*)message, sizeof(Message_ack)); |
ontvangen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| char incoming[BUFFERSIZE];
Message_ack *ack;
incoming = connection->recieve();
if(incoming != NULL) {
message = (Message*)incoming;
if(message->get_packet_type() == 1) {
ack = (Message_ack*)incoming;
if(ack->get_acknowledge()) printf("continue!\n\n");
else printf("probleempje?\n\n");
}
} |
ik geef gewoon met de functie recieve() de hele verkregen ontvangst buffer naar de controller.
Maar als ik het zo draai, dan krijg ik dus: probleempje op mijn scherm. Iemand daar een idee over?
[ Voor 26% gewijzigd door k0ewl op 06-10-2006 15:43 ]
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
Met andere woorden, hoe weet je dat je Message in 1 buffer past?
Pointer casts gaan (bijna) altijd goed.
Zie ook: http://www.parashift.com/...-standards.html#faq-27.11
[ Voor 19% gewijzigd door TheNameless op 06-10-2006 15:27 ]
Ducati: making mechanics out of riders since 1946
@hierboven:
maar hoe zou jij dan een object oversturen. Je hebt dan een pointer nodig en omdat ik werk met inheritance moet ik wel casten. Voor de rest wordt er ook nergens in mijn programma casts uitgevoerd.
Owja, mijn buffer is 8K groot, kun jezelf instellen. Die is wel groot genoeg. Straks misschien nog ietsje groter maken zodat ik er dan 10K file's in mee kan sturen.
[ Voor 23% gewijzigd door k0ewl op 06-10-2006 17:51 ]
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| class IOutStream { bool Send(char* chars) = 0; bool Send(int &int) = 0; // etc? } // een of andere socket class laten inheriten class IInStream { bool Receive(....) = 0; // etc } class IMessage { IMessage(enum msgType); protected: enum m_msgType; public: bool SendPrivate(IOutStream& os) = 0; // Remember to call baseclass implementation first bool ReceivePrivate(IInStream& os) = 0; // Remember to call baseclass implementation first } // al je messages laten inheriten class SomeMessage : IMessage(msgType1) class Socket : IOutStream; bool Send(IOutStream& os) { return os.Send(m_msgType) && SendPrivate(os); } IMessage* Receive(IInStream& instream) { enum MsgType msgType; inStream.Receive(&msgType); IMessage* msg; switch (msgType) { case msgType1: msg = new SomeMessage(msgType); //etc... } if (msg) { msg.ReceivePrivate(instream); } } |
das al 1 methode om zoiets min of meer behoorlijk op te lossen. Ze is allesbehalve af en heeft wel wat onderhoud nodig. Ze heeft bovendien niet meteen de mogelijkheid om variable length dingen (zoals strings) eenvoudig uit te schrijven. Wil je dat doen, dan kan je ze uitbreiden om bvb Type/Length/Value combinaties uit te schrijven. Dat is waarschijnlijk de eenvoudigste manier om allerhande data over te brengen als je de exacte lengte niet kent.
niet vergeten dat je later zelfs eenvoudig hetzelfde naar een outputstream of filestream kan schrijven.
Dit kan je toepassen als je weet welke data er volgt (bvb bij CORBA/IIOP)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| bool Send(socket, int& val); bool Receive(socket, int& val); bool Send(socket, char& val); bool Receive(socket, char& val); template<class T> bool Send(socket, vector<T>& array); template<class T> bool Receive(socket, vector<T>& array); enz... class Message { private: int a, b; public: bool Send(socket) { return Send(socket, a) && Send(socket, b); } bool Receive(socket) { return Receive(socket, a) && Receive(socket, b); } } |
ASSUME makes an ASS out of U and ME
Ik had de grote van een Message geschreven als output ipv de lengte van het pakket. Daar zat de fout.
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
This can no longer be ignored.
Of als sizeof(T) aan de andere kant anders is. Of als je een C++ object stuurt. Casten naar char const* kan alleen bij PODs. (Plain Old Data) en dat is het resultaat alleen bruikbaar binnen hetzelfde programma.__fred__ schreef op donderdag 05 oktober 2006 @ 21:19:
Als je specifiek je pointer naar je object cast naar een char * dan gaat dat wel werken. Als lengte kan je dan sizeof(T) gebruiken.
Maar wat nou als je object pointers naar andere objecten bevat? dat resulteert aan de andere kant van de lijn in een page fault en een dikke crash, omdat die pointer in het niets staat te wijzen.
[ Voor 11% gewijzigd door MSalters op 07-10-2006 11:18 ]
Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein
Volgens mij return je een lokale buffer vanuit receivek0ewl schreef op vrijdag 06 oktober 2006 @ 14:43:
Ook dat probleem heb ik al opgelost. Maar ik heb een veel aparter probleem.
ik geef gewoon met de functie recieve() de hele verkregen ontvangst buffer naar de controller.
Maar als ik het zo draai, dan krijg ik dus: probleempje op mijn scherm. Iemand daar een idee over?
Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.
its me again.
Het programma opzich werkt nu gewoon alleen we liepen tegen een probleem aan. We willen namelijk een Secure Socket Layer over de huidige sockets.
Nu zijn daar alleen helemaal geen fatsoenlijke voorbeelden van te vinden. Overal krijg je al voor gecompileerde programma's en niet een klein stukje source met uitleg.
Heeft iemand misschien nog een goede link of iets wat mij op weg kan helpen?
Alvast bedankt.
A byte walks into a bar and orders a pint. Bartender asks him "What's wrong?" Byte says "Parity error." Bartender nods and says "Yeah, I thought you looked a bit off."
Wil je toch code, kun je misschien eens in code.google.com zoeken naar een functie uit de OpenSSL lib.
ASSUME makes an ASS out of U and ME