/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
Gode råd søges
Fra : Morten Winther


Dato : 04-04-03 12:00

Hej

Jeg har nu langt om længe fået skrevet en chat i C++. Det er menigen at man
telnet'er ind på en port og så chatter - altså intet fancy.

Jeg er dog total newbie så jeg vil lige høre om nogen vil komme med lidt
feedback til min kode? Ingen grund til at tillægge sig dårlige vaner her fra
start. Især tror jeg at jeg har blandet C og C++ sammen, hvad burde jeg
ændre?

Nu hører man jo også så meget om buffer-overflow o.s.v. Er der nogen
sikkerhedsbrister i min kode?

Jeg var også meget i tvivl om de pointers jeg bruger. Er de rigtige?

Det er lidt besværligt at overføre mit map til de forskellige funktioner.
Kan jeg sætte map<int, Deltager_info> alle uden for main, og så bruge det
direkte i alle funktioner?

Lidt tunge spørgsmål da i jo nok skal læse hele koden igennem for at svare,
men jeg håber i vil give et par gode råd.


Hilsen Morten


#include <map>
#include <iostream>
#include <string>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace std;

// port we're listening on
#define PORT 7913

// fildescripters
fd_set master; // master file descriptor list
fd_set read_fds;

// struct
struct Deltager_info
{
int fd_socket;
string nick;
int mode;
string buffer;
};

// hent til næste \r
string hent(string *s)
{
string temp;

// find første \n
unsigned int f = s->find("\r",0);

if(f != string::npos)
{

// temp
temp = s->substr(0, f);

// resten
*s = s->substr(f+1, s->size() - f -1);
}
else
{
temp = "";
//return 0;
}

//return
return temp;
}

// send til alle
void send_til_alle(map<int, Deltager_info> *al, string besked)
{
besked += "\r\n";
// loop
for(map<int, Deltager_info>::iterator it = (*al).begin(); it !=
(*al).end(); ++it)
{
//kun til dem der er helt inde
if(it->second.mode == 2)
{
if (FD_ISSET(it->first, &master))
{
send(it->first, besked.c_str(), strlen(besked.c_str()), 0);
}
}
}
}

// sæt nick
void hentnick(map<int, Deltager_info> *al, int afsender, string navn)
{
// burde checke om navn er ok samt ledig

// gem i map
(*al)[afsender].nick = navn;
(*al)[afsender].mode = 2; // chatmode

// fortæl til verden
send_til_alle(&(*al), "** Server: " + navn + " er kommet ind i chatten");
}

// behandle
void behandle(map<int, Deltager_info> *al, int id)
{
string denne;

//cout << (*al)[id].buffer << endl;

while ((denne = hent(&(*al)[id].buffer)) != "")
{

if((*al)[id].mode == 1)
{
//nick
hentnick(&(*al), id, denne);
}
else if((*al)[id].mode == 2)
{
// chat
send_til_alle(&(*al), ((*al)[id].nick + ": " + denne));
}

// serverpromt
cout << "Buffer " << id << ": " << denne << endl;
}

}


int main()
{

// erklær
string ind;
map<int, Deltager_info> alle;

struct sockaddr_in myaddr; // server address
struct sockaddr_in remoteaddr; // client address
int listener; // listening socket descriptor
int newfd; // newly accept()ed socket descriptor
char buf[256];
int nbytes;
int yes=1; // for setsockopt() SO_REUSEADDR, below
socklen_t addrlen;
int fdmax;
string besked_start = "Velkommen til TelnetChat v1.0\r\nIndtast nick\r\n";


// start
cout << "Server startet!" << endl;

// clear the master and temp sets
FD_ZERO(&master);
FD_ZERO(&read_fds);

// get the listener
if((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}

// lose the pesky "address already in use" error message
if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))
== -1) {
perror("setsockopt");
exit(1);
}

// bind
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = INADDR_ANY;
myaddr.sin_port = htons(PORT);
memset(&(myaddr.sin_zero), '\0', 8);

if(bind(listener, (struct sockaddr *)&myaddr, sizeof(myaddr)) == -1) {
perror("bind");
exit(1);
}

// listen
if (listen(listener, 10) == -1) {
perror("listen");
exit(1);
}

// add the listener to the master set
FD_SET(listener, &master);
fdmax = listener; // so far, it's this one

// listener -> map
alle[listener].nick = "lytter";
alle[listener].mode = 100;
alle[listener].buffer = "";

// hovedloop
while(1) {

// copy it
read_fds = master;

// cout << alle.size() << endl;

// select
if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(1);
}

// loop gennem sockets
for(map<int, Deltager_info>::iterator it = alle.begin(); it !=
alle.end(); ++it)
{
// test om socket er ok
if (FD_ISSET(it->first, &read_fds))
{
// er det lytteren
if (it->first == listener)
{
// handle new connections
addrlen = sizeof(remoteaddr);

// hent ny socket - udskriv hvis fejl
if ((newfd = accept(listener, (struct sockaddr *)&remoteaddr,
&addrlen)) == -1) {
perror("accept");
}
else // ny socket ok
{
// add to master set
FD_SET(newfd, &master);

// keep track of the maximum
if (newfd > fdmax) {
fdmax = newfd;
}

// indsæt i map
alle[newfd].mode = 1; // 1 = venter på brugernavn

// indtast handle
send(newfd, besked_start.c_str(), strlen(besked_start.c_str()), 0);

printf("selectserver: new connection from %s on socket %d\n",
inet_ntoa(remoteaddr.sin_addr), newfd);
}

}
else // det er ikke lytteren = alm client
{
// handle data from a client
if ((nbytes = recv(it->first, buf, sizeof(buf), 0)) <= 0)
{
// got error or connection closed by client
if (nbytes == 0)
{
// connection closed
printf("selectserver: socket %d hung up\n", it->first);
}
else
{
perror("recv");
}

// farvel
close(it->first); // bye!

// remove from master set
FD_CLR(it->first, &master);

// fortæl verden
if(it->second.mode == 2)
{
send_til_alle(&alle, ("** Server: " + it->second.nick + " har
forladt chatten"));
}

// fjern fra map
alle.erase(it->first);
}
else // rigtig data fra client
{
// gem ny tekst i buffer
alle[it->first].buffer += *buf;

// find ud af om input er afsluttet
unsigned int f = alle[it->first].buffer.find("\r",0);

if(f != string::npos)
{
behandle(&alle, it->first);

}
} // data fra client
} // ikke lytteren
} // if socket ok
} // socket loop
} // hovedloop

// slut
return 0;
}
--
/ morten

"There are only 10 types of people in the world: Those who understand
binary, and those who don't"



 
 
Lasse Westh-Nielsen (04-04-2003)
Kommentar
Fra : Lasse Westh-Nielsen


Dato : 04-04-03 13:45

"Morten Winther" <mail@is.invalid> wrote in message
news:b6jofv$co4$1@sunsite.dk...
> Hej
>
> jeg vil lige høre om nogen vil komme med lidt feedback til min kode?

Jeg synes du kunne bruge lidt mere OO, du praktiserer vist ren og skær
procedurel programmering. Det kunne hjælpe med at modularisere din kode ud
på flere, mere overskuelige filer, og dermed gøre det nemmere at udvide og
vedligeholde:

/* Fil: DeltagerInfo.h */

class DeltagerInfo
{
public:
DeltagerInfo(string nick, ...) /* contructor */

string getNick() { return this->nick; };
void setNick(string nick) { this->nick = nick; };
...

private:
string nick;
...
};


> Det er lidt besværligt at overføre mit map til de forskellige funktioner.
> Kan jeg sætte map<int, Deltager_info> alle uden for main, og så bruge det
> direkte i alle funktioner?

Et lille fif er typedef:

typedef MyCoolMap map<int, Deltager_info>;

Så kan du skrive såden her, som jeg synes ser pænere ud:

MyCoolMap* coolMap = new MyCoolMap();

void send_til_alle(MyCoolMap* al, string besked)...

Der giver ikke ekstra performance, men det kan gøre din kode "pænere".

Mvh Lasse


--
<signature>
Lasse Westh-Nielsen
lasse@daimi.au.dk
</signature>




Robert Larsen (04-04-2003)
Kommentar
Fra : Robert Larsen


Dato : 04-04-03 14:04

Lasse Westh-Nielsen wrote:
> "Morten Winther" <mail@is.invalid> wrote in message
> news:b6jofv$co4$1@sunsite.dk...

>
>>Det er lidt besværligt at overføre mit map til de forskellige funktioner.
>>Kan jeg sætte map<int, Deltager_info> alle uden for main, og så bruge det
>>direkte i alle funktioner?
>
>
> Et lille fif er typedef:
>
> typedef MyCoolMap map<int, Deltager_info>;
Næsten rigtigt

typedef map<int, Deltager_info> MyCoolMap;

> Så kan du skrive såden her, som jeg synes ser pænere ud:
>
> MyCoolMap* coolMap = new MyCoolMap();
>
> void send_til_alle(MyCoolMap* al, string besked)...
>
> Der giver ikke ekstra performance, men det kan gøre din kode "pænere".
>
> Mvh Lasse
>
>
> --

VH

Robert


Robert Larsen (04-04-2003)
Kommentar
Fra : Robert Larsen


Dato : 04-04-03 13:58

Morten Winther wrote:
> Hej
>
> Jeg har nu langt om længe fået skrevet en chat i C++. Det er menigen at man
> telnet'er ind på en port og så chatter - altså intet fancy.
>
> Jeg er dog total newbie så jeg vil lige høre om nogen vil komme med lidt
> feedback til min kode? Ingen grund til at tillægge sig dårlige vaner her fra
> start. Især tror jeg at jeg har blandet C og C++ sammen, hvad burde jeg
> ændre?
>
> Nu hører man jo også så meget om buffer-overflow o.s.v. Er der nogen
> sikkerhedsbrister i min kode?
>
> Jeg var også meget i tvivl om de pointers jeg bruger. Er de rigtige?
>
> Det er lidt besværligt at overføre mit map til de forskellige funktioner.
> Kan jeg sætte map<int, Deltager_info> alle uden for main, og så bruge det
> direkte i alle funktioner?
>
> Lidt tunge spørgsmål da i jo nok skal læse hele koden igennem for at svare,
> men jeg håber i vil give et par gode råd.
>
>
>

Well.....jeg så ikke umiddelbart nogen fejl men jeg har da et par
kommentarer til din programmeringsstil. Brug mange flere og mindre
funktioner (eller endnu bedre..indkapsling i objekter). En god regel er
at en funktion ikke må fylde mere en én skærm og allerhøjst have to
nestede scopes:

while(something)
{
   if(somethingElse)
   {
      //Ikke flere if's, case's eller løkker herunder.
      //Hvis yderligere er nødvendige så læg
      //dem i en funktion for sig selv og kald den.
   }
   else
   {
   }
}

Ellers bliver det for uoverskueligt. Din main slutter med:
}
} // data fra client
} // ikke lytteren
} // if socket ok
} // socket loop
} // hovedloop

// slut
return 0;
}

Lige i overkanten efter min mening.
Med små funktioner er det meget lettere at spotte mulige fejlkilder og
senere at udvidde koden.

En anden ting er at holde sig til ét sprog (menneskesprog). Du har
variabler som 'listener', 'newfd' og 'yes', men også 'alle' og
funktioner som 'send_til_alle'. Der er forstyrrende at læse, så hold dig
til engelsk (så får du heller ikke problemer med æøå).

Sidst men ikke mindst. Dit program er meget funktions orienteret. Du
bruger godt nok C++ her og der men du definerer ikke dine egne objekter
og programmerer ikke objekt orienteret. At bruge C++ objekter er ikke
nok. Derimod kan man godt programmere objekt orienteret selvom man
bruger almindelig C (gtk+ biblioteket er et godt eksempel). Det er lidt
smag og behag om man vil bruge objekter men det er noget nemmere at
organisere sin kode hvis man programmerer objekt orienteret.

VH
Robert


Anders J. Munch (04-04-2003)
Kommentar
Fra : Anders J. Munch


Dato : 04-04-03 15:43

"Robert Larsen" <Xrcl@ttpcom.com> wrote:
>
> En anden ting er at holde sig til ét sprog (menneskesprog). Du har
> variabler som 'listener', 'newfd' og 'yes', men også 'alle' og
> funktioner som 'send_til_alle'. Der er forstyrrende at læse, så hold dig
> til engelsk (så får du heller ikke problemer med æøå).

Ja, jeg kender ikke nogen programmører, der ikke programmerer i
dangelsk eller har gjort det tidligere, men det er nu noget rod.

Man skal vælge et sprog. Mere specifikt, man skal vælge det sprog man
forstår bedst. Uanset typografiske småirritationer.

mvh. Anders



Bertel Lund Hansen (04-04-2003)
Kommentar
Fra : Bertel Lund Hansen


Dato : 04-04-03 16:31

Anders J. Munch skrev:

>Ja, jeg kender ikke nogen programmører, der ikke programmerer i
>dangelsk eller har gjort det tidligere, men det er nu noget rod.

Det gør jeg nu, bl.a. fordi en del gode varabelnavne er
reserverede, f.eks. "new". Så tager jeg "ny" i stedet for. Jeg
bruger endda også f.eks. "naeste".

>Man skal vælge et sprog. Mere specifikt, man skal vælge det sprog man
>forstår bedst. Uanset typografiske småirritationer.

Hvis jeg skulle vælge ét sprog til variabelnavne, blev det
engelsk fordi æøå giver ballade.

--
Bertel
http://bertel.lundhansen.dk/   FIDUSO: http://fiduso.dk/

Robert Larsen (04-04-2003)
Kommentar
Fra : Robert Larsen


Dato : 04-04-03 18:20

Bertel Lund Hansen wrote:
> Anders J. Munch skrev:
>
>
>>Ja, jeg kender ikke nogen programmører, der ikke programmerer i
>>dangelsk eller har gjort det tidligere, men det er nu noget rod.
>
>
> Det gør jeg nu, bl.a. fordi en del gode varabelnavne er
> reserverede, f.eks. "new". Så tager jeg "ny" i stedet for. Jeg
> bruger endda også f.eks. "naeste".
>
>
>>Man skal vælge et sprog. Mere specifikt, man skal vælge det sprog man
>>forstår bedst. Uanset typografiske småirritationer.
>
>
> Hvis jeg skulle vælge ét sprog til variabelnavne, blev det
> engelsk fordi æøå giver ballade.
>

De fleste firmaer har også en code convention som specificerer, hvordan
man programmerer i firmaet, f.eks. hvordan man skal skrive variabel
navne, funktions navne, klasse navne, om der skal være mellemrum mellem
operatorer og operander, osv. osv. De steder jeg har arbejdet har det
også været et krav, at alle navne og kommentarer var på engelsk, så det
er en god skik at få indøvet.

VH
Robert


Anders J. Munch (05-04-2003)
Kommentar
Fra : Anders J. Munch


Dato : 05-04-03 12:35

"Bertel Lund Hansen" <nospamfor@lundhansen.dk> skrev:
> >Man skal vælge et sprog. Mere specifikt, man skal vælge det sprog man
> >forstår bedst. Uanset typografiske småirritationer.
>
> Hvis jeg skulle vælge ét sprog til variabelnavne, blev det
> engelsk fordi æøå giver ballade.

Jeg har prøvet alle tre, dansk, dangelsk og engelsk. Dansk er den
klare vinder. Det er lettere at skrive, og det er lettere at
læse. Klarhed og præcision stiger.

Da først jeg havde besluttet mig for at de var en pris værd at betale,
så holdt ae, oe og aa op med at genere mig, nær så meget. I
dangelsk-årene var jeg konstant irriteret over dem og substituerede
ofte med danske og engelske synonymer for at slippe for dem. Nu hvor
jeg skriver dansk, vælger jeg bare det rigtige ord, uanset.

- Anders




Robert Larsen (06-04-2003)
Kommentar
Fra : Robert Larsen


Dato : 06-04-03 13:40

Anders J. Munch wrote:
> "Bertel Lund Hansen" <nospamfor@lundhansen.dk> skrev:
>
>>>Man skal vælge et sprog. Mere specifikt, man skal vælge det sprog man
>>>forstår bedst. Uanset typografiske småirritationer.
>>
>>Hvis jeg skulle vælge ét sprog til variabelnavne, blev det
>>engelsk fordi æøå giver ballade.
>
>
> Jeg har prøvet alle tre, dansk, dangelsk og engelsk. Dansk er den
> klare vinder. Det er lettere at skrive, og det er lettere at
> læse. Klarhed og præcision stiger.
>
> Da først jeg havde besluttet mig for at de var en pris værd at betale,
> så holdt ae, oe og aa op med at genere mig, nær så meget. I
> dangelsk-årene var jeg konstant irriteret over dem og substituerede
> ofte med danske og engelske synonymer for at slippe for dem. Nu hvor
> jeg skriver dansk, vælger jeg bare det rigtige ord, uanset.
>
> - Anders
>
>
>

Derhjemme har man heldigvis den frihed, at man kan gøre hvad man vil,
men langt de fleste firmaer kræver, at man skriver på engelsk, så hvis
man har tænkt sig at gå prof., så er det en god idé at vænne sig til det
engelske. Firmaer bruger jo outsourcing og måske integration af deres
software med udenlandske firmaer/kunder, så der må helst ikke være nogle
sprogmæssige problemer med koden.

VH
Robert


Anders J. Munch (06-04-2003)
Kommentar
Fra : Anders J. Munch


Dato : 06-04-03 14:56

"Robert Larsen" <Xrobert@the-playground.dk> skrev:
>Firmaer bruger jo outsourcing og måske integration af deres
> software med udenlandske firmaer/kunder, så der må helst ikke være nogle
> sprogmæssige problemer med koden.

YAGNI.

mvh. Anders




Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408924
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste