C++ Socket Server / Client
-
Moin!
Ich habe folgende Programme (siehe unten) geschrieben.
Wie muss ich den Server bzw. den Client umschreiben, dass der Server alle Nachrichten an alle Clienten weiterleitet?
Außerdem soll der Server alle Aktionen (Nachrichten, Clientenadressen etc) speichern (auf die Festplatte).Die Clienten sollen die Nachrichten empfangen und senden können? (C++ 11 Thread?).
Danke
Server
//#pragma comment( lib,"ws2_32.lib" ) #include <windows.h> #include <winsock2.h> // bei manchan compilern muss man nur windows.h includieren (zB VC++) #include <stdio.h> #define MAX_CLIENTS 10 int startWinsock(void) { WSADATA wsa; return WSAStartup(MAKEWORD(2,0),&wsa); } int main() { long rc; SOCKET acceptSocket; //SOCKET connectedSocket; SOCKADDR_IN addr; char buf[256]; char buf2[300]; // zusätzliche Variabeln FD_SET fdSet; SOCKET clients[MAX_CLIENTS]; int i; // Winsock starten rc=startWinsock(); if(rc!=0) { printf("Fehler: startWinsock, fehler code: %ld\n",rc); return 1; } else { printf("Winsock gestartet!\n"); } // Socket erstellen acceptSocket=socket(AF_INET,SOCK_STREAM,0); if(acceptSocket==INVALID_SOCKET) { printf("Fehler: Der Socket konnte nicht erstellt werden, fehler code: %d\n",WSAGetLastError()); return 1; } else { printf("Socket erstellt!\n"); } // Socket binden memset(&addr,0,sizeof(SOCKADDR_IN)); addr.sin_family=AF_INET; addr.sin_port=htons(12345); addr.sin_addr.s_addr=INADDR_ANY; // gewisse compiler brauchen hier ADDR_ANY rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN)); if(rc==SOCKET_ERROR) { printf("Fehler: bind, fehler code: %d\n",WSAGetLastError()); return 1; } else { printf("Socket an port 12345 gebunden\n"); } // In den listen Modus rc=listen(acceptSocket,10); if(rc==SOCKET_ERROR) { printf("Fehler: listen, fehler code: %d\n",WSAGetLastError()); return 1; } else { printf("acceptSocket ist im listen Modus....\n"); } for(i=0;i<MAX_CLIENTS;i++) { clients[i]=INVALID_SOCKET; } while(1) { FD_ZERO(&fdSet); // Inhalt leeren FD_SET(acceptSocket,&fdSet); // Den Socket der verbindungen annimmt hinzufügen // alle gültigen client sockets hinzufügen (nur die die nicht INVALID_SOCKET sind) for(i=0;i<MAX_CLIENTS;i++) { if(clients[i]!=INVALID_SOCKET) { FD_SET(clients[i],&fdSet); } } rc=select(0,&fdSet,NULL,NULL,NULL); // nicht vergessen den ersten parameter bei anderen betriebssystem anzugeben if(rc==SOCKET_ERROR) { printf("Fehler: select, fehler code: %i\n",WSAGetLastError()); return 1; } // acceptSocket is im fd_set? => verbindung annehmen (sofern es platz hat) if(FD_ISSET(acceptSocket,&fdSet)) { // einen freien platz für den neuen client suchen, und die verbingung annehmen for(i=0;i<MAX_CLIENTS;i++) { if(clients[i]==INVALID_SOCKET) { clients[i]=accept(acceptSocket,NULL,NULL); printf("Neuen Client angenommen (%d)\n",i); break; } } } // prüfen wlecher client sockets im fd_set sind for(i=0;i<MAX_CLIENTS;i++) { if(clients[i]==INVALID_SOCKET) { continue; // ungültiger socket, d.h. kein verbunder client an dieser position im array } if(FD_ISSET(clients[i],&fdSet)) { rc=recv(clients[i],buf,256,0); // prüfen ob die verbindung geschlossen wurde oder ein fehler auftrat if(rc==0 || rc==SOCKET_ERROR) { printf("Client %d hat die Verbindung geschlossen\n",i); closesocket(clients[i]); // socket schliessen clients[i]=INVALID_SOCKET; // seinen platz wieder freigeben } else { buf[rc]='\0'; // daten ausgeben und eine antwort senden printf("Client %d hat folgendes gesandt: %s\n",i,buf); // antwort senden sprintf(buf2,"Du mich auch %s\n",buf); send(clients[i],buf2,(int)strlen(buf2),0); } } } } }Client
#include <windows.h> #include <winsock2.h> #include <stdio.h> //Prototypen int startWinsock(void); int main() { long rc; SOCKET s; SOCKADDR_IN addr; char buf[256]; // Winsock starten rc=startWinsock(); if(rc!=0) { printf("Fehler: startWinsock, fehler code: %d\n",rc); return 1; } else { printf("Winsock gestartet!\n"); } // Socket erstellen s=socket(AF_INET,SOCK_STREAM,0); if(s==INVALID_SOCKET) { printf("Fehler: Der Socket konnte nicht erstellt werden, fehler code: %d\n",WSAGetLastError()); return 1; } else { printf("Socket erstellt!\n"); } // Verbinden memset(&addr,0,sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten addr.sin_family=AF_INET; addr.sin_port=htons(12345); // wir verwenden mal port 12345 addr.sin_addr.s_addr=inet_addr("127.0.0.1"); // zielrechner ist unser eigener rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR)); if(rc==SOCKET_ERROR) { printf("Fehler: connect gescheitert, fehler code: %d\n",WSAGetLastError()); return 1; } else { printf("Verbunden mit 127.0.0.1..\n"); } // Daten austauschen while(rc!=SOCKET_ERROR) { printf("\nZeichenfolge eingeben [max 256]: "); gets(buf); send(s,buf,strlen(buf),0); rc=recv(s,buf,256,0); if(rc==0) { printf("Server hat die Verbindung getrennt..\n"); break; } if(rc==SOCKET_ERROR) { printf("Fehler: recv, fehler code: %d\n",WSAGetLastError()); break; } buf[rc]='\0'; printf("\nServer antwortet: %s\n",buf); } closesocket(s); WSACleanup(); return 0; } int startWinsock(void) { WSADATA wsa; return WSAStartup(MAKEWORD(2,0),&wsa); }
-
Du hast doch bei deinem Server eine Struktur, die alle sockets von eingegangenen Verbindungen enthält.
Wenn du jetzt also in deiner Nachrichtenschleife von einem der Sockets etwas zugeschickt bekommst, dann sendest du halt als Konsequenz diese Nachricht an alle Sockets in dieser Struktur weiter. Außer natürlich an den, von dem die Nachricht kommt.
So fern ich mich erinnere (länger her) werden bei Clients, die die Verbindungen trennen auch Nachrichten mit irgendeinem Sondercodd geschickt - die natürlich nicht weiter schicken sondern entsprechend verarbeiten.Die Problematik bei "Clients sollen empfangen und senden können" verstehe ich nicht.
Du horchst auf den Server (permanent, non blocking) und das senden wird wohl als Resultat von irgendeiner GUI Aktion geschehen.
-
m.sc.m schrieb:
Ich habe folgende Programme (siehe unten) geschrieben.
Wirklich?
m.sc.m schrieb:
Wie muss ich den Server bzw. den Client umschreiben, dass der Server alle Nachrichten an alle Clienten weiterleitet?
Wenn es dein Programm ist, solltest du das wissen.
Aber schau mal in Zeile 115ff. Die Achricht schickst du nicht nur an client[i] sondern auch an alle anderen gültigen Einträge aus client.m.sc.m schrieb:
Außerdem soll der Server alle Aktionen (Nachrichten, Clientenadressen etc) speichern (auf die Festplatte).
Da machst du an derselben Stelle.
m.sc.m schrieb:
Die Clienten sollen die Nachrichten empfangen und senden können? (C++ 11 Thread?).
Tun sie das nicht?
Oder möchtest du auf das Warten bei der Eingabe verzichten?.
Nebenbei istgetsböse und abgekündigt. Das verwendet man seit 25 Jahren nicht mehr.Und mit C++ hat der Code nichts zu tun. Das ist reines C.
-
Also in Zeile 62 wird die Eingabe des Clienten (Benutzers) abgefangen und anschließend an den Server gesendet.
In Zeile 72 wird die (eventuelle) Nachricht vom Server ausgegeben.
Hier möchte ich aber, dass alle Nachrichten, die vor, bei und direkt beim absenden geschickte Nachricht sofort ausgegeben wird und nicht "irgendwann" bzw "teilweise" danach.Danke
-
DirkB schrieb:
m.sc.m schrieb:
Ich habe folgende Programme (siehe unten) geschrieben.
Wirklich?
m.sc.m schrieb:
Wie muss ich den Server bzw. den Client umschreiben, dass der Server alle Nachrichten an alle Clienten weiterleitet?
Wenn es dein Programm ist, solltest du das wissen.
Aber schau mal in Zeile 115ff. Die Achricht schickst du nicht nur an client[i] sondern auch an alle anderen gültigen Einträge aus client.m.sc.m schrieb:
Außerdem soll der Server alle Aktionen (Nachrichten, Clientenadressen etc) speichern (auf die Festplatte).
Da machst du an derselben Stelle.
m.sc.m schrieb:
Die Clienten sollen die Nachrichten empfangen und senden können? (C++ 11 Thread?).
Tun sie das nicht?
Oder möchtest du auf das Warten bei der Eingabe verzichten?.
Nebenbei istgetsböse und abgekündigt. Das verwendet man seit 25 Jahren nicht mehr.Und mit C++ hat der Code nichts zu tun. Das ist reines C.
Ich hab es mit 2 Clients getestet und sie erhalten nur ihre eigenen Nachrichten und erhalten keine anderen Nachrichten....
-
m.sc.m schrieb:
Ich hab es mit 2 Clients getestet und sie erhalten nur ihre eigenen Nachrichten und erhalten keine anderen Nachrichten....
liest du:
DirkB schrieb:
m.sc.m schrieb:
Wie muss ich den Server bzw. den Client umschreiben, dass der Server alle Nachrichten an alle Clienten weiterleitet?
Wenn es dein Programm ist, solltest du das wissen.
Aber schau mal in Zeile 115ff. Die Nachricht schickst du nicht nur an client[i] sondern auch an alle anderen gültigen Einträge aus client.
-
Entweder habe ich grad zu viel Alkohol intus

aber wie muss ich dann es ändern, wenn zum Beispiel der client 0, Client 1 und Client 2 die Nachrichten der anderen Clienten auch empfangen?
Danke
-
Dieser Code kommt nach Zeile 113, aber noch im else-Zweig
for(j=0;j<MAX_CLIENTS;j++) { if (j==i) continue; // aktueller client? if(clients[j]==INVALID_SOCKET) { continue; // ungültiger socket, d.h. kein verbunder client an dieser position im array } send(clients[j],buf,(int)strlen(buf),0); }
-
Falsches Subforum - ist WinAPI und nicht C++.
-
Wenn du eine nachricht an alle senden willst musst du das mit einer schleife machen wie die hier:
else { buf[rc]='\0'; // daten ausgeben und eine antwort senden printf("Client %d hat folgendes gesandt: %s\n",i,buf); //Jetzt an alle clients die nachricht schicken for(int a = 0;a < MAX_CLIENTS;a++) { if(a != i) { //Nachricht nur schicken wenn es nicht der sender ist send(clients[a],buf,(int)strlen(buf),0); } } }Wenn der client empfangen und gleichzeitig die eingabe evrarbeiten soll musst du threads benutzen mit der funktion CreateThread geht das ganz gut
mehr infos über threads gibt google 
Und wenn du die nachrichten von den clients speischern willst scheib sie in eine
txt datei dazu gibt viel in googlesry wegen der rechtschreibung

-
helper_D schrieb:
Wenn der client empfangen und gleichzeitig die eingabe evrarbeiten soll musst du threads benutzen
Mit
kbhit()(ist ja Windows und C) sollte das auch gehen. (Nicht die Threads, aber das nicht-blocklierende lesen von der Konsole)Wenn du aber mal eine GUI dafür machen willst, musst du das Programm eh umbauen.