Forum: PC-Programmierung Socket UDP Verbindung und mehrere Clients


von user (Gast)


Lesenswert?

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?

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

select()

von user (Gast)


Lesenswert?

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.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

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?

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

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
von user (Gast)


Lesenswert?

Das mit einem Thread wie funktioniert dies?

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von user (Gast)


Lesenswert?

Guten Morgen Wilhelm,

ich verwende die Win-API.

von user (Gast)


Lesenswert?

Das Ziel ist, dass mit nur einer Applikation mehrer Teilnehmer 
angesteurt werden sollen.

von Rolf M. (rmagnus)


Lesenswert?

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.

von user (Gast)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

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
von user (Gast)


Lesenswert?

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?

von Wilhelm M. (wimalopaan)


Lesenswert?

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!!!

von Peter II (Gast)


Lesenswert?

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.

von user (Gast)


Lesenswert?

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
}

von Peter II (Gast)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

Die Konstruktor-like Funktion _objectUDPPor(...) fehlt.

von user (Gast)


Lesenswert?

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
}

von user (Gast)


Lesenswert?

Die Funktion select blockiert nun nicht mehr mein Programm.
Die Funktion objectUDPPort_Receive und die Thread Funktion UDPThread 
befinden sich innerhalb vom Objekt objectUDPPort.

von Wilhelm M. (wimalopaan)


Lesenswert?

user schrieb:
> Die Funktion select blockiert nun nicht mehr mein Programm.

Oh, durch Handauflegen?

von user (Gast)


Lesenswert?

Ich hab im Netz recherchiert.

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von user (Gast)


Lesenswert?

Im Prinzip habe ich die Thread Funktion mit der select Funktion 
erweitert.

von Der Andere (Gast)


Lesenswert?

Auf Deutsch: solange irgendwelche Codeschnipsel aus dem Netz 
zusammengebastelt bis es anscheinend funktioniert.

von Wilhelm M. (wimalopaan)


Lesenswert?

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 ?

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

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?

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

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
Noch kein Account? Hier anmelden.