Hallo zusammen,
ich habe vor kurzem angefangen mir C++ beizubringen und habe dazu ein Spiel programmiert.
Jetzt versuche ich am Beispiel eines anfachen Chatprogramms zu verstehen, wie man mit Winsockets Daten versendet.
Ich bin soweit, dass ich einen einfachen Server habe, der, immer wenn er eine Nachricht bekommt, diese Nachricht leicht verändert zurückschickt.
Mein Client soll prüfen ob er eine nachricht empfangen kann und falls nicht, in std::cin springen um eine Nachricht schreiben zu können.
Mir ist bewusst, dass so wie es jetzt ist, ich keine Nachricht empfangen kann, solange ich in std::cin feststecke. - das ist ok...
Jetzt habe ich das Problem, dass mein Client gar nicht bis zur Zeile (85)
kommt, sonder bei der darüberliegenden Stelle (Zeile 68)
stehen bleibt.
Wieso ist das so? Ich denke ich habe nicht ganz verstanden wie select() funktioniert.
Nach meinem Verständnis, lässt select(), zumindest in meinem Code, alle Clients in der Clientliste fdSet stehen, bei denen es Daten zu empfangen gibt. Sind keine Daten zu empfangen dann ist fdSet eben leer.
Hier mein Client:
Und hier mein Server:
Ich bedanke mich schon mal im Voraus!
ich habe vor kurzem angefangen mir C++ beizubringen und habe dazu ein Spiel programmiert.
Jetzt versuche ich am Beispiel eines anfachen Chatprogramms zu verstehen, wie man mit Winsockets Daten versendet.
Ich bin soweit, dass ich einen einfachen Server habe, der, immer wenn er eine Nachricht bekommt, diese Nachricht leicht verändert zurückschickt.
Mein Client soll prüfen ob er eine nachricht empfangen kann und falls nicht, in std::cin springen um eine Nachricht schreiben zu können.
Mir ist bewusst, dass so wie es jetzt ist, ich keine Nachricht empfangen kann, solange ich in std::cin feststecke. - das ist ok...
Jetzt habe ich das Problem, dass mein Client gar nicht bis zur Zeile (85)
Code:
cout << "send: ";
cin.getline(sendbuf, 256);
kommt, sonder bei der darüberliegenden Stelle (Zeile 68)
Code:
rc = select(0, &fdSet, NULL, NULL, NULL);
stehen bleibt.
Wieso ist das so? Ich denke ich habe nicht ganz verstanden wie select() funktioniert.
Nach meinem Verständnis, lässt select(), zumindest in meinem Code, alle Clients in der Clientliste fdSet stehen, bei denen es Daten zu empfangen gibt. Sind keine Daten zu empfangen dann ist fdSet eben leer.
Hier mein Client:
Code:
#pragma comment(lib, "ws2_32.lib")
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <Winsock2.h>
#include <Windows.h>
using namespace std;
char sendbuf[256];
char recvbuf[256];
int main()
{
//Hilfsvariable
long rc;
u_long iMode = 1;
FD_SET fdSet;
//Winsock starten
WSADATA wsaData;
rc = WSAStartup(MAKEWORD(2, 0), &wsaData);
if (rc == 0)
cout << "wsaStartup() \t\t succesful" << endl;
else
cout << "error wsaStartup():" << WSAGetLastError() << endl;
SOCKET s;
sockaddr_in addr;
s = socket(AF_INET, SOCK_STREAM, 0);
//ioctlsocket(s, FIONBIO, &iMode);
if (s != INVALID_SOCKET)
{
cout << "s socket()\t\t succesful" << endl;
}
else
{
cout << "error s socket():" << WSAGetLastError() << endl;
}
//Adressinformationen
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_family = AF_INET;
addr.sin_port = htons(54345);
int addrlen = sizeof(addr);
rc = connect(s, (struct sockaddr*)&addr, addrlen);
if (rc != INVALID_SOCKET)
{
cout << "connect()\t\t succesful" << endl;
}
else
{
cout << "error connect():" << WSAGetLastError() << endl;
}
while (1)
{
memset(&sendbuf, 0, sizeof(sendbuf));
memset(&recvbuf, 0, sizeof(recvbuf));
FD_ZERO(&fdSet); // Inhalt leeren
FD_SET(s, &fdSet); // Den Socket der verbindungen annimmt hinzufügen
rc = select(0, &fdSet, NULL, NULL, NULL);
if (rc == SOCKET_ERROR)
{
printf("Fehler: select, fehler code: %s\n", WSAGetLastError());
return 1;
}
if (FD_ISSET(s, &fdSet))
{
rc = recv(s, recvbuf, 256, 0);
recvbuf[rc] = '\0';
// daten ausgeben und eine antwort senden
cout << "Client hat folgendes gesandt" << endl;
cout << recvbuf << endl;
// antwort senden
}
cout << "send: ";
cin.getline(sendbuf, 256);
rc = send(s, sendbuf, strlen(sendbuf), 0);
if (rc == SOCKET_ERROR)
{
cout << "error send():" << WSAGetLastError() << endl;
}
else
{
cout << rc << "bytes sent" << endl;
}
}
closesocket(s);
WSACleanup();
return 0;
}
Und hier mein Server:
Code:
#pragma comment(lib, "ws2_32.lib")
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <Winsock2.h>
#include <Windows.h>
using namespace std;
char recvbuf[256];
char sendbuf[256];
char buf2[300];
int main()
{
u_long iMode = 1;
FD_SET fdSet;
SOCKET clients[10];
int i;
//Hilfsvariable
long res;
//Windosck starten
WSADATA wsaData;
res = WSAStartup(MAKEWORD(2,0), &wsaData);
if (res == 0)
cout << "wsaStartup() \t\t succesful" << endl;
else
cout << "error wsaStartup():" <<WSAGetLastError()<< endl;
//Sockets
SOCKET acceptSocket, connectedSocket;
//acceptSocket starten
acceptSocket = socket(AF_INET,SOCK_STREAM, 0);
if (acceptSocket != INVALID_SOCKET)
{
cout << "accepSocket()\t\t succesful" << endl;
}
else
{
cout << "error acceptSocket():" << WSAGetLastError() << endl;
}
//Verbindungsinformationen
sockaddr_in info;
info.sin_addr.s_addr = inet_addr("127.0.0.1");
info.sin_family = AF_INET;
info.sin_port = htons(54345);
int infolen = sizeof(info);
res = bind(acceptSocket, (struct sockaddr*)&info, infolen);
if (res != SOCKET_ERROR)
{
cout << "bind() \t\t succesful" << endl;
}
else
{
cout << "error bind():" << WSAGetLastError() << endl;
}
//Warten auf einkommende Verbindung
res = listen(acceptSocket, SOMAXCONN);
if (res != SOCKET_ERROR)
{
cout << "listen() \t\t succesful" << endl;
}
else
{
cout << "error listen():" << WSAGetLastError() << endl;
}
for (i = 0; i<10; i++)
{
clients[i] = INVALID_SOCKET;
}
while (1)
{
FD_ZERO(&fdSet); // Inhalt leeren
FD_SET(acceptSocket, &fdSet); // Den Socket der verbindungen annimmt hinzufügen
for (i = 0; i<10; i++) // alle gültigen client sockets hinzufügen (nur die die nicht INVALID_SOCKET sind)
{
if (clients[i] != INVALID_SOCKET)
{
FD_SET(clients[i], &fdSet);
}
}
res = select(0, &fdSet, NULL, NULL, NULL); //in fdSet sind nur noch Clients bei denen es Daten uz empfangen gibt
// nicht vergessen den ersten parameter bei anderen betriebssystem anzugeben
if (res == SOCKET_ERROR)
{
printf("Fehler: select, fehler code: %s\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<10; i++)
{
if (clients[i] == INVALID_SOCKET)
{
clients[i] = accept(acceptSocket, NULL, NULL);
printf("Neuen Client angenommen (%d)\n", i);
break;
}
}
}
for (i = 0; i<10; 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))
{
res = recv(clients[i], recvbuf, 256, 0);
// prüfen ob die verbindung geschlossen wurde oder ein fehler auftrat
if (res == 0 || res == 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
{
recvbuf[res] = '\0';
// daten ausgeben und eine antwort senden
printf_s("Client %d hat folgendes gesandt: %s\n", i, recvbuf);
// antwort senden
sprintf_s(buf2, "Du mich auch %s\n", recvbuf);
send(clients[i], buf2, (int)strlen(buf2), 0);
}
}
}
}
closesocket(connectedSocket);
closesocket(acceptSocket);
WSACleanup();
return 0;
}
Ich bedanke mich schon mal im Voraus!
Zuletzt bearbeitet: