Server/Client-TCP asynchron (winsock) // FD_WRITE Problem
Brauche ich Eure Hilfe, denn ich habe zwei Konsolen-Anwendung in C++ : ein client schicken zu können, wie viele Strings wie möglich zu einem server (in der Reihenfolge zu senden, Koordinaten). Es gelang mir, um einer Sperrung Steckdose, aber wie habe ich das zu integrieren, nachdem in einer Entwicklungs-Plattform (3D ÜBER Virtools), die nennen mein script jeden frame, habe ich keine andere Lösung als die Verwendung von asynchronen sockets.
*Mein problem ist, dass ich nur E-saite einmal, und nachdem ich nicht erhalten, FD_WRITE mehr...*
Diese beginnen, fahren Sie mich verrückt, so jede Hilfe wird sehr geschätzt werden (ich bin ein Anfänger in der Programmierung), vielen Dank im Voraus an alle, die das Gefühl ein wenig besorgt über mein problem
Hier ist mein code,
Server
#include <winsock2.h>
#include <Windows.h>
#include <conio.h>
#pragma comment(lib, "ws2_32.lib")
#define SOCKET_ERRNO WSAGetLastError()
#define ADDRESS "127.0.0.1"
#define PORT 1234
static SOCKET ListenFirstFreePort()
{
struct sockaddr_in addr;
int len = sizeof(addr);
SOCKET hSocket;
//Create socket
hSocket = socket( PF_INET, SOCK_STREAM, 0 );
if( hSocket == INVALID_SOCKET )
{
printf( "socket() error %d\n", SOCKET_ERRNO );
exit(1);
}
//Connexion setting for local connexion
addr.sin_family = AF_INET ;
addr.sin_addr.s_addr = inet_addr(ADDRESS);
addr.sin_port = htons (PORT);
//bind socket
if ( bind( hSocket, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR )
{
printf( "bind() error %d\n", SOCKET_ERRNO );
exit(1);
}
//listen
if ( listen( hSocket, 100) == SOCKET_ERROR )
{
printf( "listen() error %d\n", SOCKET_ERRNO );
exit(1);
}
return hSocket;
}
void main()
{
WSADATA stack_info;
SOCKET ahSocket[2];
WSAEVENT ahEvents[2];
DWORD dwEvent;
WSANETWORKEVENTS NetworkEvents;
int rc;
//Initialize Winsock
WSAStartup(MAKEWORD(2,0), &stack_info) ;
//Create events
ahEvents[0] = WSACreateEvent();
ahEvents[1] = WSACreateEvent();
//Create listening socket
ahSocket[0] = ListenFirstFreePort();
rc = WSAEventSelect(ahSocket[0], ahEvents[0], FD_ACCEPT );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
while (TRUE)
{
//Waiting for so;ething to happen
//Basically we'll firstly receive the connexion of the client socket
//and then we'll be notificated when there will be some data to read
//look for events
dwEvent = WSAWaitForMultipleEvents( 2, ahEvents, FALSE, WSA_INFINITE, FALSE);
switch (dwEvent)
{
case WSA_WAIT_FAILED:
printf("WSAEventSelect: %d\n", WSAGetLastError());
break;
case WAIT_IO_COMPLETION:
case WSA_WAIT_TIMEOUT:
break;
default:
//if there is one dwEvent-WSA_WAIT_EVENT_0 has to be substracted so as to dwEvent correspond to the index of the concerned socket
dwEvent -= WSA_WAIT_EVENT_0;
//enumeration of the events on the socket[dwEvent]
if (SOCKET_ERROR == WSAEnumNetworkEvents(ahSocket[dwEvent], ahEvents[dwEvent], &NetworkEvents))
{
printf("WSAEnumNetworkEvent: %d lNetworkEvent %X\n",
WSAGetLastError(), NetworkEvents.lNetworkEvents);
NetworkEvents.lNetworkEvents = 0;
}
else
{
if (FD_CLOSE & NetworkEvents.lNetworkEvents)
{
printf( "FD_CLOSE ok (dwEvent=%d)\n", dwEvent );
printf( "press a key to exit\n" );
getch(); //require conio.h
WSACloseEvent( ahEvents[0] );
WSACloseEvent( ahEvents[1] );
exit(0);
}
if (FD_READ & NetworkEvents.lNetworkEvents)
{
char szBuffer[256]; int cbRecv;
//Only the second socket expect to receive data
printf( "FD_READ ok (dwEvent=%d)\n", dwEvent );
//read data
cbRecv = recv( ahSocket[dwEvent], szBuffer, sizeof(szBuffer) - 1, 0 );
if( cbRecv <= 0 )
{
printf( "recv() error %d\n", SOCKET_ERRNO );
exit(1);
}
//On ecrit ce paquet (On remet le 0 au cas ou le paquet
//ait ete coupe en 2 - je sais, ca n'arrivera jamais en local)
//we put the 0 in case it has been cut - unlikey to happen on local network
szBuffer[cbRecv] = 0;
//write data in console window
printf( "socket %d : '%s'\n", dwEvent, szBuffer );
}
}
if (FD_ACCEPT & NetworkEvents.lNetworkEvents)
{
struct sockaddr_in addrAccept;
int lenAccept;
lenAccept = sizeof( addrAccept );
//we should have dwEvent=0
printf( "accept ok (dwEvent=%d)\n", dwEvent );
//we create another socket to accept the connexion with the client socket
ahSocket[1] = accept(ahSocket[dwEvent], (struct sockaddr *)&addrAccept, &lenAccept);
//we want to be informed on when we'll be able read data from it
rc = WSAEventSelect(ahSocket[1], ahEvents[1], FD_READ|FD_CLOSE );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
}
}
}
}
Client
#include <winsock2.h>
#include <conio.h>
#include <time.h>
#pragma comment(lib, "ws2_32.lib")
#define SOCKET_ERRNO WSAGetLastError()
#define ADDRESS "127.0.0.1"
#define PORT 1234
SOCKET ConnectToPort()
{
struct sockaddr_in addr;
SOCKET hSocket;
u_long arg; int err;
//Create socket
hSocket = socket( PF_INET, SOCK_STREAM, 0 );
if( hSocket == INVALID_SOCKET )
{
printf( "socket() error %d\n", SOCKET_ERRNO );
exit(1);
}
//Connexion setting for local connexion
addr.sin_family = AF_INET ;
addr.sin_addr.s_addr = inet_addr(ADDRESS);
addr.sin_port = htons (PORT);
//Connect
if( connect( hSocket, (struct sockaddr *)&addr, sizeof(addr) ) == SOCKET_ERROR )
{
//As we are in non-blocking mode we'll always have the error
//WSAEWOULDBLOCK whichis actually not one
if( SOCKET_ERRNO != WSAEWOULDBLOCK )
{
printf( "connect() error (%d)\n", SOCKET_ERRNO );
exit(1);
}
}
return hSocket;
}
void main()
{
int initClockTime;
WSADATA stack_info;
SOCKET ahSocket[1];
WSAEVENT ahEvents[1];
DWORD dwEvent;
WSANETWORKEVENTS NetworkEvents;
int rc;
//Initialize Winsock
WSAStartup(MAKEWORD(2,0), &stack_info) ;
//Create event
ahEvents[0] = WSACreateEvent();
//Create and connect a socket on the server socket
ahSocket[0]= ConnectToPort();
//not sure if I have to use or not
/*u_long arg = 1;
ioctlsocket( ahSocket[0] , FIONBIO, &arg );*/
//the application wants to receive notification of a completed connection
rc = WSAEventSelect(ahSocket[0], ahEvents[0], FD_CONNECT );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
while (TRUE)
{
//look for events
dwEvent = WSAWaitForMultipleEvents( 1, ahEvents, FALSE, 1000, FALSE);
switch (dwEvent)
{
case WSA_WAIT_FAILED:
printf("WSAEventSelect: %d\n", WSAGetLastError());
break;
case WAIT_IO_COMPLETION:
case WSA_WAIT_TIMEOUT:
break;
default:
printf("while\n");
//if there is one dwEvent-WSA_WAIT_EVENT_0 has to be substracted so as to dwEvent correspond to the index of the concerned socket
dwEvent -= WSA_WAIT_EVENT_0;
//enumeration of the events on the socket[dwEvent]
if (SOCKET_ERROR == WSAEnumNetworkEvents(ahSocket[dwEvent], ahEvents[dwEvent], &NetworkEvents))
{
printf("WSAEnumNetworkEvent: %d lNetworkEvent %X\n", WSAGetLastError(), NetworkEvents.lNetworkEvents);
NetworkEvents.lNetworkEvents = 0;
}
else
{
if (FD_CONNECT & NetworkEvents.lNetworkEvents)
{
//connexion is OK
printf( "FD_CONNECT ok (dwEvent=%d)\n", dwEvent );
//now that we are connected we want to send data or be aware when the other socket is disconnected
rc = WSAEventSelect(ahSocket[dwEvent], ahEvents[dwEvent], FD_CLOSE | FD_WRITE );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
}
if (FD_CLOSE & NetworkEvents.lNetworkEvents)
{
printf( "FD_CLOSE ok (dwEvent=%d)\n", dwEvent );
printf( "press a key to exit\n" );
getch();
WSACloseEvent( ahEvents[0] );
exit(0);
}
if (FD_WRITE & NetworkEvents.lNetworkEvents)
{
char szBuffer[256]; int cbBuffer;
printf( "FD_WRITE ok (dwEvent=%d)\n", dwEvent );
//create string and return the size
cbBuffer = sprintf( szBuffer, "Coucou", dwEvent );
//send the string with 0 at the end
rc = send( ahSocket[dwEvent], szBuffer, cbBuffer + 1, 0 );
if (SOCKET_ERROR == rc)
{
printf("WSAEnumNetworkEvent: %d lNetworkEvent %X\n", WSAGetLastError(), NetworkEvents.lNetworkEvents);
}
//not sure if I have to use it
//WSAResetEvent(ahEvents[0]);
}
}
}
}
}
herunterladen .cpp-Dateien : https://www.dropbox.com/s/pjuipz7v4iwr5ea/Clientserver%20TCP.zip
InformationsquelleAutor user1637091 | 2012-08-30
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sind Sie nicht immer
FD_WRITE
- Benachrichtigungen nach den ersten ein, weil Sie nicht unter Berücksichtigung folgender Absatz aus die Dokumentation:Nachdem Sie Ihren ersten Anruf zu
send()
, der sockel ist noch beschreibbar, da das ausgehende Puffer nicht voll ist. Solange Sie noch Daten zu senden, halten Sie den Aufrufsend()
bis es Berichte, die einWSAWOULDBLOCK
Fehler, der angibt, der Puffer voll ist. An diesem Punkt, haben Sie, um zu verfolgen Ihre übrigen Daten, bis Sie eineFD_WRITE
Benachrichtigung der socket schreibbar ist wieder so Sie können weiterhin senden Ihre restlichen Daten aus, wo Sie aufgehört haben.rc = 0; int dada = 0; while ( dada != WSAEWOULDBLOCK) { rc = send( ahSocket[dwEvent], szBuffer, cbBuffer + 1, 0 ); if (SOCKET_ERROR == rc) { dada = WSAGetLastError(); printf("WSAEnumNetworkEvent: %d lNetworkEvent %X\n",WSAGetLastError(), NetworkEvents.lNetworkEvents); } }
(sorry, ich wusste nicht gelingt, formatieren Sie es richtig)InformationsquelleAutor Remy Lebeau
Ich würde empfehlen zu schauen, in regelmäßigen
select()
für nicht-blockierende I/O-ersten. Hier ein paar links für Sie, um loszulegen:Regelmäßige wählen Sie() in Windows bekannten performance-Probleme. Es ist die Leistung verringert sich Linear O(N) mit der Anzahl der sockets.
Ja,
select()
hat Probleme überall, nicht nur Windows, aber es ist ein Ausgangspunkt für das Verständnis des Konzepts.InformationsquelleAutor Nikolai Fetissov