Hallo, eine bestehende C Applikation soll dahingend erweitert werden, dass mit eine Applikation mehrere Clients erzeugt und diese jeweils UDP Nachrichten versenden und empfangen können. Die vorhandene C Applikation benutzt einen Thread in dem die ankommenden Daten empfangen und weitergereicht werden. Was müsste ich tun, damit ich mehrere Client mit einer C Anwendung verwalten kann?
Ich habe schon einiges getestet sogar mit der select Funktion leider ohne Erfolg. Wenn ich zum Beispiel die select Funktion benutze läuft das Programm nicht weiter.
Dann machst Du irgendeinen grundsätzlichen Fehler bei der Verwendung von select(). Hast Du Dir denn wenigstens die Unmengen an Diskussionen bei Stackoverflow zu dem Thema select() mit UDP angeschaut, aufmerksam durchgelesen UND verstanden?
user schrieb: > Ich habe schon einiges getestet sogar mit der select Funktion leider > ohne Erfolg. Wenn ich zum Beispiel die select Funktion benutze läuft das > Programm nicht weiter. Es blockiert in select() solange, bis ein datagram eintrifft bzw. man kann es so parametrieren.
user schrieb: > Hallo, > > eine bestehende C Applikation soll dahingend erweitert werden, dass mit > eine Applikation mehrere Clients erzeugt und diese jeweils UDP > Nachrichten versenden und empfangen können. > Die vorhandene C Applikation benutzt einen Thread in dem die ankommenden > Daten empfangen und weitergereicht werden. Was müsste ich tun, damit ich > mehrere Client mit einer C Anwendung verwalten kann? Warum nicht ein paar threads pre-create-en (vorher erzeugen) und die alle in recvfrom() blockieren lassen. Einer bekommt das datagramm und läuft weiter. Natürlich ist ein bißchen Buchführung notwendig, um immer genug threads zu haben ...
:
Bearbeitet durch User
user schrieb: > Das mit einem Thread wie funktioniert dies? POSIX oder Win-API? Bei POSIX: schau Dir die pthread_... systemcalls an. Allerdings sehe ich an Deiner Antwort, dass das Thema Nebenläufigkeit für Dich wohl Neuland ist. Vielleicht nimmst Du erst mal ein Buch zur Hand.
Das Ziel ist, dass mit nur einer Applikation mehrer Teilnehmer angesteurt werden sollen.
Wozu überhaupt select() oder mehrere Threads? Es ist doch UDP. Da kann doch doch eh der eine Socket die Daten von allen Clients empfangen, so lange sie an den selben Port senden.
Meine derzeitge Applikation sieht so aus, dass ich für jeden Teilnehmer die bind Funktion ausführe und nur einen Thread starte. Im Thread wird dann die Funktion recvfrom zum Empfangen von Daten benutzt. Allerdings funktioniert dies nicht so wie es sein sollte. Der Empfang funktioniert nicht korrekt.
Rolf M. schrieb: > Wozu überhaupt select() oder mehrere Threads? Es ist doch UDP. Da kann > doch doch eh der eine Socket die Daten von allen Clients empfangen, so > lange sie an den selben Port senden. Naja, der eine Thread könnte recht lange brauchen, um die Antwort zusammen zu stellen, dann kann er nicht wieder zu einem recvfrom() zurückkehren. Und mit select() kann man schauen, ob ein nachflgender syscall blockieren würde. Das liefert eine Multiplexlösung ... braucht man bei pre-threading nicht.
:
Bearbeitet durch User
Hier wurden nun einige Vorschläge gemacht. Fakt ist das meine Anwendung mit nur einem Thread nicht funktioniert. Wie würde das ganze dann mit einem Thread und zusätzlich der select Funktion aussehen?
user schrieb: > Hier wurden nun einige Vorschläge gemacht. Fakt ist das meine Anwendung > mit nur einem Thread nicht funktioniert. Wie würde das ganze dann mit > einem Thread und zusätzlich der select Funktion aussehen? Woher sollen wir das wissen??? Dann zeige doch erst mal Deinen Code!!!
user schrieb: > Fakt ist das meine Anwendung > mit nur einem Thread nicht funktioniert. Fakt ist, das select bei viele Anwendungen funktioniert - also wird der Fehler bei dir legen. > Wie würde das ganze dann mit > einem Thread und zusätzlich der select Funktion aussehen? mal schnell etwas mit Threads machen, ist eine sehr schlechte Idee. Da muss man sich schon ein paar Gedanken über Synchronisation und Kommunikation der Threads machen. Dafür müsste aber wissen was genau das Programm machen soll.
Für das Empfangen von UDP Nachrichten wird ein Thread benutzt. Die Empfangsfunktion kann dann außerhalb von diesem Object aufgerufen werden.
1 | objectUDP* UDPPort[MAXUDPPORTS]; |
2 | HANDLE hUdpThread; |
3 | |
4 | DWORD WINAPI UDPThread(LPVOID lpParameter) |
5 | {
|
6 | int i; |
7 | fd_set read_handles; |
8 | struct timeval timeout_interval; |
9 | int retval; |
10 | int max_server_handle = 0; |
11 | |
12 | while(1) |
13 | {
|
14 | FD_ZERO(&read_handles); |
15 | for (i = 0; i < MAXUDPPORTS; i++) |
16 | {
|
17 | if (UDPPort[i]) |
18 | {
|
19 | FD_SET(UDPPort[i]->Socket, &read_handles); |
20 | }
|
21 | }
|
22 | |
23 | timeout_interval.tv_sec = 1; |
24 | timeout_interval.tv_usec = 0; |
25 | |
26 | retval = select(max_server_handle + 1, &read_handles, NULL, NULL, &timeout_interval); |
27 | if (retval == -1) |
28 | {
|
29 | printf("Select error\n"); |
30 | //error
|
31 | }
|
32 | else if (retval == 0) |
33 | {
|
34 | printf("timeout\n"); |
35 | }
|
36 | else
|
37 | {
|
38 | //good
|
39 | for (i = 0; i < MAXUDPPORTS; i++) |
40 | {
|
41 | if (UDPPort[i]) |
42 | {
|
43 | if (FD_ISSET(UDPPort[i]->Socket, &read_handles)) |
44 | {
|
45 | if (UDPPort[i]->m_ReceiveBufferLen == 0) |
46 | {
|
47 | int rcvlen = sizeof(sockaddr_in); |
48 | int Len; |
49 | if ((Len = recvfrom(UDPPort[i]->Socket, UDPPort[i]->m_ReceiveBuffer, UDPBufferLen, 0, (sockaddr*)&UDPPort[i]->m_ReceiveAddr, &rcvlen)) < 0) |
50 | {
|
51 | perror("Error in recvfrom."); |
52 | break; |
53 | }
|
54 | |
55 | printf("\nData received on socket %d:", i); |
56 | |
57 | UDPPort[i]->m_ReceiveBufferLen = Len; |
58 | if (UDPPort[i]->m_InterruptControl) UDPPort[i]->pM->Operate(UDPPort[i]); |
59 | }
|
60 | }
|
61 | }
|
62 | }
|
63 | }
|
64 | }
|
65 | return 0; |
66 | }
|
67 | |
68 | int objectUDPPort_Receive(objectUDP* pInst, char* pMsg) |
69 | {
|
70 | int Len; |
71 | |
72 | Len=pInst->m_ReceiveBufferLen; |
73 | if (Len) |
74 | {
|
75 | int CountMax=Len; |
76 | int i; |
77 | |
78 | if (MaxLen<Len) CountMax=MaxLen; |
79 | for (i=0;i<CountMax;i++) pMsg[i]=pInst->m_ReceiveBuffer[i]; |
80 | pInst->m_ReceiveBufferLen=0; |
81 | }
|
82 | return Len; |
83 | }
|
84 | |
85 | objectUDPPort *UPort[2]; |
86 | |
87 | void main(void) |
88 | {
|
89 | |
90 | UPort[0] = (objectUDPPort *)malloc(sizeof(objectUDPPort)); |
91 | UPort[1] = (objectUDPPort *)malloc(sizeof(objectUDPPort)); |
92 | |
93 | _objectUDPPort(UPort[0], "192.168.0.1", 1000, 1001); // UDP-Client |
94 | _objectUDPPort(UPort[1], "192.168.0.2", 1000, 1002); // UDP-Client |
95 | |
96 | while(1) |
97 | {
|
98 | int Len; |
99 | char Buffer[100]; |
100 | Len = UPort[0]->pM->Receive(UPort[0], Buffer, 512, 0); |
101 | if (Len) |
102 | {
|
103 | |
104 | }
|
105 | }
|
106 | }
|
user schrieb: > Für das Empfangen von UDP Nachrichten wird ein Thread benutzt. > Die Empfangsfunktion kann dann außerhalb von diesem Object aufgerufen > werden. kannst du jetzt noch mal genau schreiben, was passiert bzw. wo das Problem liegt. Du hattest ja geschrieben, das select blockiert, aber du hast du einen timeout von 1 sekunde - länger dürfte es nicht blockieren.
Die Konstruktor-like Funktion _objectUDPPor(...) fehlt.
Konstruktor:
1 | void _objectUDPPort(objectUDPPort* pInst, char* ToIPAddr, int DstPort, int SrcPort) |
2 | {
|
3 | pInst->pM->Destroy = (void(*)(void*))*objectUDPPort_Destroy; |
4 | pInst->pM->Send = (void(*)(void*,char*,int,int))*objectUDPPort_Send; |
5 | pInst->pM->Receive = (int (*)(void*,char*,int,int))*objectUDPPort_Receive; |
6 | |
7 | pInst->m_ReceiveBufferLen=0; |
8 | pInst->m_PortIndex = 0; |
9 | |
10 | unsigned long Identifyer; |
11 | hndUdpThread = CreateThread(NULL, 0, UDPThread, (LPVOID)0, 0, &Identifyer); |
12 | |
13 | // Socket DLL oeffnen
|
14 | WSADATA wsaData; |
15 | if ( WSAStartup( MAKEWORD( 2, 2 ), &wsaData )!=0 ) |
16 | MessageBox(0,(LPCWSTR)"UDP",(LPCWSTR)"WSA Socket DLL not found!",MB_OK); |
17 | |
18 | // Index fuer globle Objektdaten suchen
|
19 | while (UDPPort[pInst->m_PortIndex] && pInst->m_PortIndex<2) pInst->m_PortIndex++; |
20 | if (pInst->m_PortIndex == 2) |
21 | { // Keine freie Hardwarerecource |
22 | pInst->m_PortIndex = -1; |
23 | return; |
24 | }
|
25 | |
26 | // Client Configuration
|
27 | pInst->m_SendAddr.sin_family=AF_INET; |
28 | pInst->m_SendAddr.sin_addr.S_un.S_addr=inet_addr(ToIPAddr); |
29 | pInst->m_SendAddr.sin_port=htons(DstPort); |
30 | |
31 | pInst->m_ReceiveAddr.sin_addr.S_un.S_addr=0; |
32 | |
33 | // Socket oeffnen
|
34 | pInst->Socket = socket(AF_INET, SOCK_DGRAM, 0); |
35 | |
36 | if (pInst->Socket != INVALID_SOCKET) |
37 | {
|
38 | sockaddr_in name; |
39 | name.sin_family = AF_INET; |
40 | name.sin_port = htons(SrcPort); |
41 | name.sin_addr.S_un.S_addr = htonl(INADDR_ANY); |
42 | if (bind(pInst->Socket, (sockaddr*)&name, sizeof(name)) == SOCKET_ERROR) |
43 | {
|
44 | closesocket(pInst->Socket); |
45 | pInst->Socket = INVALID_SOCKET; |
46 | }
|
47 | else
|
48 | {
|
49 | int result = 0; |
50 | int Timeout_ms = 1; |
51 | |
52 | if (result == SOCKET_ERROR) |
53 | {
|
54 | closesocket(pInst->Socket); |
55 | pInst->Socket = INVALID_SOCKET; |
56 | }
|
57 | else
|
58 | {
|
59 | UDPPort[pInst->m_PortIndex] = pInst; |
60 | }
|
61 | }
|
62 | }
|
63 | else
|
64 | {
|
65 | int Err = WSAGetLastError(); |
66 | }
|
67 | }
|
Die Funktion select blockiert nun nicht mehr mein Programm. Die Funktion objectUDPPort_Receive und die Thread Funktion UDPThread befinden sich innerhalb vom Objekt objectUDPPort.
user schrieb: > Ich hab im Netz recherchiert. Oh Mann, WAS hast Du denn geändert, dass es nun geht? Lass uns teilhaben ... jedenfalls die, die Dir helfen wollten.
Im Prinzip habe ich die Thread Funktion mit der select Funktion erweitert.
Auf Deutsch: solange irgendwelche Codeschnipsel aus dem Netz zusammengebastelt bis es anscheinend funktioniert.
user schrieb: > Im Prinzip habe ich die Thread Funktion mit der select Funktion > erweitert. Das select() (mit timeout) war vorher auch schon drin ... aber lt. Deiner Aussage ohne Erfolg. Als was war es ?
user schrieb: > Ich hab im Netz recherchiert. Aha. Stammen die obigen Quellcodeabschnitte denn auch "aus dem Netz"? Unter welchen Lizenzbedingungen darfst Du sie denn verwenden? Bei den meisten Open-Source-Lizenzen werden doch die Nennung des Urhebers und der Lizenzbedingungen selbst verlangt. Oder hast Du etwa eine juristisch durchaus relevante Urheberrechtsverletzung begangen?
Der Andere schrieb: > Auf Deutsch: solange irgendwelche Codeschnipsel aus dem Netz > zusammengebastelt bis es anscheinend funktioniert. Solch einen Typen hatte ich auch einmal eingestellt, der völlig wahlfrei irgendwelche Codeschnipsel aneinanderreihte und dem noch nicht einmal bewusst war, dass man diese Teile zumindest über Funktionsaufrufe, Datenstrukturen o.ä. miteinander verbinden musste. Und derjenige war sogar Diplom-Informatiker, frisch von der FH! Kurze Zeit später war er wieder arbeitslos, fand aber schnell einen weiteren Job, aus dem er sogar noch schneller wieder hochkant herausflog. Der Typ hatte wirklich keinerlei Vorstellungen davon, was er überhaupt falsch machte.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.