Ik ben het volgende aan het proberen te maken:
Een server die bij het starten een socket() maakt, bind() en laat listen()-en en daarna een thread start die in een oneindige loop nieuwe connections accept() en voor elke connection een thread maakt om te recv()-en. Ik probeer dit zo portable mogelijk te houden dus daarom gebruik ik pthreads.
Omdat ik natuurlijk alles netjes wil opruimen loop ik tegen het volgende aan. accept() kan de thread blocken op het moment dat ik de server wil stoppen (hoogstwaarschijnlijk eigenlijk). Om dit op te lossen dacht ik de socket gewoon te close()-en waardoor de accept() een error geeft en de thread unblockt. Onder windows werkt dit wel, onder freebsd echter niet.. (ik zie nooit de printf("quitting accept-thread\n"))
Een ander probleem is dat ik weet dat het geen goede oplossing is om te controleren op een return van -1 van accept() om vervolgens alles op te ruimen en te stoppen. Beter zou zijn om errno te controleren maar waar ik mee zit is: is dat thread-safe? (met andere woorden: kan het niet gebeuren dat door een functie ergens anders in het programma errno gezet wordt voordat ik deze kan controleren?)
raar is overigens dat wanneer ik onder freebsd het programma run deze ook zonder errors gewoon afsluit (hij komt dus voorbij de join die normaal gesproken moet blocken tot de andere thread stopt)
Een server die bij het starten een socket() maakt, bind() en laat listen()-en en daarna een thread start die in een oneindige loop nieuwe connections accept() en voor elke connection een thread maakt om te recv()-en. Ik probeer dit zo portable mogelijk te houden dus daarom gebruik ik pthreads.
Omdat ik natuurlijk alles netjes wil opruimen loop ik tegen het volgende aan. accept() kan de thread blocken op het moment dat ik de server wil stoppen (hoogstwaarschijnlijk eigenlijk). Om dit op te lossen dacht ik de socket gewoon te close()-en waardoor de accept() een error geeft en de thread unblockt. Onder windows werkt dit wel, onder freebsd echter niet.. (ik zie nooit de printf("quitting accept-thread\n"))
C:
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
| int *sck_Listen; pthread_t thid_Listen; void *accept_connections(void *ptr) /* * Continue to accept incoming connections */ { pthread_t tid; int *new_fd; int sin_size; struct sockaddr_in their_addr; new_fd = (int *)malloc(sizeof(int)); sin_size = sizeof(struct sockaddr_in); for(;;) /* keep trying to make new connections forever */ { if((*new_fd = accept(*sck_Listen, (struct sockaddr *)&their_addr, &sin_size)) == -1) /* block thread until new connection is made */ { printf("quitting accept-thread\n"); free(new_fd); new_fd = NULL; pthread_exit(0); } printf("passed accept()\n"); if(pthread_create(&tid,NULL,connection,new_fd) != 0); /* create new thread to handle the new connection */ } } int start_server(int port) { struct sockaddr_in server_addr; #ifdef _WIN32 /* WSAStartup is required on win32-systems */ WSADATA wsaData; if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) return 1; #endif sck_Listen = (int *)malloc(sizeof(int)); *sck_Listen = socket(PF_INET, SOCK_STREAM, 0); /* create new streaming socket; auto-detect protocol */ server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* auto-detect local ip-address */ memset(&(server_addr.sin_zero), '\0', 8); /* zero the rest of the struct */ if(bind(*sck_Listen, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) != 0) return 1; /* Bind socket */ if(listen(*sck_Listen,BACKLOG) != 0) return 1; /* start listening on socket */ if(pthread_create(&thid_Listen,NULL,accept_connections,sck_Listen) != 0) return 1; /* create thread to accept new connections */ return 0; /* server is started */ } int main(int argc, char* argv[]) { if(start_server(80) != 0) printf("Error Starting Server\n"); printf("Press Any Key...\n"); while(!fgetc(stdin)); #ifdef _WIN32 closesocket(*sck_Listen); #else if(close(*sck_Listen) != 0) printf("Error Closing socket\n"); #endif pthread_join(thid_Listen,NULL); free(sck_Listen); sck_Listen = NULL; while(!fgetc(stdin)); return 0; } |
Een ander probleem is dat ik weet dat het geen goede oplossing is om te controleren op een return van -1 van accept() om vervolgens alles op te ruimen en te stoppen. Beter zou zijn om errno te controleren maar waar ik mee zit is: is dat thread-safe? (met andere woorden: kan het niet gebeuren dat door een functie ergens anders in het programma errno gezet wordt voordat ik deze kan controleren?)
raar is overigens dat wanneer ik onder freebsd het programma run deze ook zonder errors gewoon afsluit (hij komt dus voorbij de join die normaal gesproken moet blocken tot de andere thread stopt)