Forum: PC-Programmierung Socket UDP Verbindung und mehrere Clients


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von user (Gast)


Bewertung
0 lesenswert
nicht 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


Bewertung
1 lesenswert
nicht lesenswert
select()

von user (Gast)


Bewertung
0 lesenswert
nicht 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


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
Das mit einem Thread wie funktioniert dies?

von Wilhelm M. (wimalopaan)


Bewertung
-1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen Wilhelm,

ich verwende die Win-API.

von user (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Das Ziel ist, dass mit nur einer Applikation mehrer Teilnehmer 
angesteurt werden sollen.

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
-1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
Die Konstruktor-like Funktion _objectUDPPor(...) fehlt.

von user (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


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

Oh, durch Handauflegen?

von user (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
Ich hab im Netz recherchiert.

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht 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)


Bewertung
-2 lesenswert
nicht lesenswert
Im Prinzip habe ich die Thread Funktion mit der select Funktion 
erweitert.

von Der Andere (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Auf Deutsch: solange irgendwelche Codeschnipsel aus dem Netz 
zusammengebastelt bis es anscheinend funktioniert.

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht 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


Bewertung
0 lesenswert
nicht 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


Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.