Willkommen ~Gast!
Registrieren || Einloggen || Hilfe/FAQ || Staff
Probleme mit der Registrierung im Forum? Melde dich unter registerEin Bild.
Autor Beitrag
000
12.03.2002, 13:46
dp
Administrator


Hi,

ich habe ein kleines Problem mit 'nem Server Code, der mehrere clients auf einmal managen soll.

Ich beschreibe mal den Fehler:
1) Server wird gestartet, keine Probs
2) Client #1 connectet (telnet), keine Probs
3) Client #2 connectet, keine Probs

jetzt geb ich bei client #2 was ein, was dann auch bei dem server als debug angezeigt wird. aber ab jetzt kann ich weder neue clients connecten, noch kann ich von client #1 was empfangen ..

es scheitert schon am select(). nachdem ich einmal von einem client lese, scheint es so als würde select _nur_ noch den file desc von diesem überwachen.

hier mein code: (dass der keine free() und close() weiss ich, ist nur zum test)

compilt unter vc++ und gcc < 3 (ka was genau, der der bei suxe 7.3 dabei is), die select() stelle ist farblich markiert

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

#ifdef WIN32
#include <winsock.h>
#else
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#endif

#ifndef WIN32
#define INVALID_SOCKET -1
#else
#define close(s) closesocket(s)
#endif

struct connection_t
{
int fd;
struct connection_t *pnext;
struct connection_t *pprev;
};
struct connection_t *g_connlist = 0;

void start_server(void);
void add_fd(int fd);
void add_connection(int fd);
void rm_connection(struct connection_t *c);

int errno;
int sd;
struct sockaddr_in server;

fd_set rfds;
int maxfd = 0;

void add_connection(int fd)
{
struct connection_t *c = malloc(sizeof(struct connection_t));

memset(c, 0, sizeof(struct connection_t));
c->fd = fd;

FD_SET(fd, &rfds);
if( fd > maxfd )
maxfd = fd;

if( g_connlist )
{
g_connlist->pnext = c;
c->pprev = g_connlist;
}
g_connlist = c;
}

/*void rm_connection(struct connection_t *c)
{
if( c->pnext )
c->pnext->pprev = c->pprev;
if( c->pprev )
c->pprev->pnext = c->pnext;

if( c == g_connlist )
g_connlist = c->pprev;

free(c);
}*/

int main(int argc, char **argv)
{
#ifdef WIN32
WSADATA wsa_data;
WSAStartup(MAKEWORD(1,1), &wsa_data);
#endif

start_server();
return 0;
}

void start_server(void)
{
int clisock;
int addrlen;
struct sockaddr_in client;
char *teststr = "welcome\n\n";
char buffer[1024];
struct connection_t *c;

FD_ZERO (&rfds);

/* create socket */
sd = socket(AF_INET, SOCK_STREAM, 0);
if( sd == INVALID_SOCKET )
{
printf("socket() failed: %s\n", strerror(errno));
exit(1);
}

maxfd = sd;

server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(7000);

/* bind, listen */
if( bind(sd, (struct sockaddr *) &server, sizeof(server)) )
{
printf("bind() failed: %s\n", strerror(errno));
exit(1);
}
listen(sd, 5);

addrlen = sizeof(client);

FD_SET(sd, &rfds);

while( 1 )
{
printf("\n #### selecting (up to fd #%d) ...\n", maxfd + 1);
if( (select(maxfd + 1, &rfds, NULL, NULL, /*&tv*/ NULL)) != -1 )
{
if( FD_ISSET(sd, &rfds) )
{
printf("server socket change, accepting connection and sending string.\n");
clisock = accept(sd, (struct sockaddr *) &client, &addrlen);
printf("client #%d connected.\n", clisock);
add_connection(clisock);

send(clisock, teststr, strlen(teststr) + 1, 0);
}
else
{
for( c = g_connlist; c; c = c->pprev )
{
if( FD_ISSET(c->fd, &rfds) )
{
printf(" --- client sock changed. (sock #%d)..\n", c->fd);
memset(buffer, 0, 1024);
recv(c->fd, buffer, 1024, 0);
printf("client data:\n%s\n\n", buffer);
}
}
}

}
else
{
printf("select() failed (%s)\n", strerror(errno));
exit(1);
}
}
}

--


Dieser Beitrag wurde am 12.03.2002 um 13:47 von Darth Paul bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
001
12.03.2002, 14:37
Prefect



Da hat einer nicht weit genug gedacht *tsts* ;)

Die übergebenen fdsets werden von select() natürlich verändert - nur dadurch funktionieren das Makro FD_ISSET (unter *nix ist fdset einfach ein Bitfeld, unter Windows ein Array mit Socketnummern).

Du muß also direkt vor dem select() ein FD_ZERO und erneutes FD_SET ausführen.

cu,
Prefect

--

Widelands - Gemütliche Aufbaustrategie, Free Software
Noch ein Blog - Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.

zum Seitenanfang zum Seitenende Profil || Suche
002
12.03.2002, 15:13
dp
Administrator


uhm *schäm*

ok danke, ich werds mal testen.

--

zum Seitenanfang zum Seitenende Profil || Suche
003
12.03.2002, 18:05
apfelkorn



hm... mal ne frage:
wärs nicht eigentlich klüger das ganze nicht verbindungsorientiert zu machen? also quasi per udp?

--

zum Seitenanfang zum Seitenende Profil || Suche
004
13.03.2002, 13:24
dp
Administrator


ok funzt perfekt, sogar unter win O_o

@apfelkorn: ka, ich habs nur zum testen gemacht ..

--

zum Seitenanfang zum Seitenende Profil || Suche
005
13.03.2002, 13:26
Prefect



UDP != verbindungsorientiert
TCP == verbindungsorientiert

SOCK_STREAM ~ verbindungsorientiert == TCP

cu,
Prefect

--

Widelands - Gemütliche Aufbaustrategie, Free Software
Noch ein Blog - Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.

zum Seitenanfang zum Seitenende Profil || Suche
006
14.03.2002, 14:40
apfelkorn



mh... prefi ist und bleibt cguru

--

zum Seitenanfang zum Seitenende Profil || Suche