I'm trying to make a chess game, through sockets.
There is a server that is responsible for sending the board to the players, to get the input and response and so on..
I've tried to create a client-server (actually 2clients and server) but it doesn't work.
The clients connect to the server properly, but the data that is delieved doesn't correct.
For example, I send "E2-C3" from the client ; the recv result (on the server side) is always 0, or it prints garbage.
Client :
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <sys/types.h>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
using namespace std;
#define SERVER_IP "1.1.1.1"
#define SERVER_PORT 8888
#define BUFFER_SIZE 1024
// server side
#define INVALID_MOVE 00
#define PLEASE_ENTER_A_MOVE 15
#define PRINT_BOARD 20
#define END_GAME 30
// client side
#define MOVE 10
int __cdecl main()
{
WSADATA info;
int errorDATA; // configuriation
int socketCreate; // create the socket - empty
SOCKADDR_IN ClientService; // configuriation (stage 3) - data of the server.
int connectResult;
char sendBuf[1024], recvbuf[1024];
int iResult;
/*Configuration*/
errorDATA = WSAStartup(MAKEWORD(2, 2), &info);
if (errorDATA == INVALID_SOCKET)
{
printf("WSAStartup failed with error : %d\n", errorDATA);
return -1;
}
/*Create empty socket*/
socketCreate = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // creating the socket "Clean - empty"
if (socketCreate == INVALID_SOCKET)
{
printf("Error number %d in creating socket!\n", WSAGetLastError());
return -1;
}
printf("Creating socket SUCCEEDED!\n");
/*Confugirate the created socket*/
ClientService.sin_family = AF_INET;
ClientService.sin_addr.s_addr = inet_addr(SERVER_IP); // server's ip
ClientService.sin_port = htons(SERVER_PORT);
/*Asking for connection*/
connectResult = connect(socketCreate, (struct sockaddr*) &ClientService, sizeof(ClientService));
while (1)
{
cout << "Please enter a move : " << endl;
cin >> sendBuf;
iResult = send(socketCreate, sendBuf, (int)strlen(sendBuf), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(socketCreate);
WSACleanup();
return 1;
}
// MOVE
iResult = recv(socketCreate, recvbuf, strlen(recvbuf), 0);
if (iResult > 0)
{
if (recvbuf[0] == '0' && recvbuf[1] == '0')
{
cout << "You've entered an illegal move. Please try again." << endl;
continue;
}
else if (recvbuf[0] == '2' && recvbuf[1] == '0')
{
// print the board.
bool keepGoing = 0;
do
{
iResult = recv(socketCreate, recvbuf, strlen(recvbuf), 0);
if (iResult > 0)
{
if (recvbuf[0] == '1' && recvbuf[1] == '5')
{
keepGoing = true;
continue;
}
}
} while (!keepGoing);
}
}
else if (iResult == 0)
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
}
printf("Bytes Sent: %ld\n", iResult);
// shutdown the connection since no more data will be sent
iResult = shutdown(socketCreate, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(socketCreate);
WSACleanup();
return 1;
}
// cleanup
closesocket(socketCreate);
WSACleanup();
cin.get();
system("pause");
return 0;
}
server:
#include <iostream>
#include <winsock2.h>
#include <string>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")
#define MAX_NUMBER_OF_PLAYERS 1
#define BUFFER_SIZE 1024
#define LIMIT 1
// server side
#define INVALID_MOVE 00
#define PLEASE_ENTER_A_MOVE 15
#define PRINT_BOARD 20
#define END_GAME 30
// client side
#define MOVE 10
using namespace std;
int main()
{
WSADATA WsaDat;
SOCKET clientsock[2];
int minsock = 0;
int numsocks = MAX_NUMBER_OF_PLAYERS;
if (WSAStartup(MAKEWORD(2, 2), &WsaDat) != 0)
{
std::cout << "WSA Initialization failed!\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
std::cout << "Socket creation failed.\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
SOCKADDR_IN serverInf;
serverInf.sin_family = AF_INET;
serverInf.sin_addr.s_addr = INADDR_ANY;
serverInf.sin_port = htons(8888);
if (bind(serverSocket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR)
{
std::cout << "Unable to bind socket!\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
listen(serverSocket, 5);
clientsock[0] = accept(serverSocket, NULL, NULL);
cout << "Client 1 has connected." << endl;
clientsock[1] = accept(serverSocket, NULL, NULL);
cout << "Client 2 has connected." << endl;
for (int i = 0; i < 2; i++)
{
cout << clientsock[i] << endl;
}
// If iMode!=0, non-blocking mode is enabled.
u_long iMode = 1;
ioctlsocket(serverSocket, FIONBIO, &iMode);
char client1_buffer[BUFFER_SIZE];
char client2_buffer[BUFFER_SIZE];
char* clientBuffer;
// until there isn't a mate.
bool gameRunning = true;
// user represents if it's user1 (0), or user2(1)
bool user = 0;
while (gameRunning)
{
if (!user)
clientBuffer = client1_buffer;
else
clientBuffer = client2_buffer;
int in = recv(clientsock[0], client1_buffer, 0, 0);
cout << in << endl;
if (in > 0)
{
// CHECKS
// MOVE COMMAND
// IF worked, send the board to both clients. if current user = 1 ==> do user to 0 | if the user = 0 => do user to 11
// ELSE, send the current client (clientsock[user]) Error message and ask for a command again.
cout << client1_buffer << endl;
cout << " IN RECV";
char* szMessage = "15";
send(clientsock[0], szMessage, strlen(szMessage), 0);
}
else if (in == 0)
{
// The connection has closed.
// REMEMBER : SAVE THE GAME SITUATION.
}
else
{
printf("recv failed: %d\n", WSAGetLastError());
// SEND ERROR MESSAGE TO BOTH CLIENTS
}
}
// Shutdown our socket
shutdown(serverSocket, SD_SEND);
// Close our socket entirely
closesocket(serverSocket);
WSACleanup();
system("pause");
return 0;
}
What Hans said. plus this:
int in = recv(clientsock[0], client1_buffer, 0, 0);
Your probably want to say this:
int in = recv(clientsock[0], client1_buffer, BUFFER_SIZE, 0);
Also, you are making a fundamental error that a lot of people make with sockets. You are assuming that your recv call on your server will return as many bytes was passed to the corresponding send call by the client. Fragmentation, segmentation, and other network stuff may cause you to receive only a partial amount of the message that was sent on the other node's send call. (Hence, TCP is a stream protocol as they say).
You should diligently check the return value from recv. Write your code as if the sender was only to going to send 1 byte at a time. You should put delimiters between your messages (a null char is fine) and loop on recv until you get a complete message. Otherwise, what seems to work fine on your own PC and on the local subnet will have strange bugs when deployed to the internet.
In the server file change
int in = recv(clientsock[0], client1_buffer, 0,0);
to
int in = recv(clientsock[0], client1_buffer, 1024,0);
change is the length of the date to be received
The problem is
strlen(recvbuf)
You probably mean
sizeof(recvbuf)
strlen(recvbuf) does not makes sense before you received the data, because your buffer contains just garbage, thus strlen() is just a bad random number generator. strlen(recvbuf) would make sense after you received the data if you would have made sure it was filled with 0. That not being the case, you can use the return value of recv() to find out how many bytes you received.
Related
I have written code in C++ which takes the x and y coordinates of a robot and sends them across a socket using a little endian. The x and y coordinates are then received on the client end of the socket where they are used to control an actor in a game. All of my code works well but I would like to analyse how efficiently the coordinates are sent and received and to do this i would like to measure the delay in the sending of the coordinates.
I looked into this and saw that getting the time that the coordinate was sent and received and then calculating the difference was the way most people spoke about doing this. However, i am just confused how i would do this in my code as i have measured the time for the program to start up the robot by using int Start = Clock() and int End = Clock() and then getting the difference. But i don't know if this would be the most effective or accurate way of measuring the delay across the socket. So, i was wondering if anybody could suggest a way in which i could do this using the code below. The server sends the coordinates, and the client receives the coordinates.
SERVER code:
#undef UNICODE
#include "pch.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <chrono>
// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")
//#define DEFAULT_BUFLEN 8
#define DEFAULT_BUFLEN 5000
#define DEFAULT_PORT "27015"
//two structures for converting the x and y back into doubles/floats
union {
float myFloatx;
unsigned char myCharsx[sizeof(float)];
} testx;
union {
float myFloaty;
unsigned char myCharsy[sizeof(float)];
} testy;
double x;
double y;
int __cdecl main(void)
{
int start = clock();
WSADATA wsaData;
int iResult;
double x;
double y;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo* result = NULL;
struct addrinfo hints;
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
//added (to send back bytes to client)----------------
SOCKET ConnectSocket = INVALID_SOCKET;
char sendvbuf[8];
int sendvbuflen = 8;
//---------------------------------------------
//Creating instances of the classes -------------------------------------------------------------------------------------------------------
Articares::Core::ArticaresComm instance;
Articares::Core::HMANData instance2;
Articares::Core::TargetParams instance3;
//Connecting to HMan -------------------------------------------------------------------------------------------------------
instance.EstablishConnection("192.168.102.1", 3000);
int end = clock();
int time = end - start;
std::cout << "time to connect = " << time << "\n";
//Starting the exercise and setting the targets --------------------------------------------------------------------------
instance.StartExercise(3);
instance.SetTransitionTime(8000, 1, 0);
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
printf("listening\n");
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
//sleep command added to stop the targets moving before the on game instructions have been read by the user
Sleep(80);
//Set target 1 with targetx = 10mm and targety = 10 mm, ‘StiffnessX’ = 100 N/m, ‘StiffnessY’ = 100 N/m, ‘target gain’ = 1,
//IF WISHING TO INCREASE THE RESISTANCE PLEASE INCREASE THE 4TH AND 5TH VALUES IN THE SetTarget() function:
instance.SetTarget("1", "10", "10", "50", "50", "0", "0", "0", "0", "0", "0", "1", "0");
instance.SetTarget("2", "10", "50", "50", "50", "0", "0", "0", "0", "0", "0", "1", "0");
instance.SetTarget("3", "50", "10", "50", "50", "0", "0", "0", "0", "0", "0", "1", "0");
// No longer need server socket
closesocket(ListenSocket);
// Receive until the peer shuts down the connection
do {
while (recv(ClientSocket, recvbuf, recvbuflen, MSG_PEEK) < 8) { ; }
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
//std::cout << " hello" << recvbuf << std::endl;
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
// Echo the buffer back to the sender
iSendResult = send(ClientSocket, recvbuf, iResult, 0);
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
}
else if (iResult == 0)
printf("Connection closing...\n");
else {
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while (false);
//Start:; allows the continual sending of coordinates to occur meaning that the program will not shutdown unless it is shutdown from the client end.
Start:;
for (int i = 0; i < 50; i++)
{
std::cout << i << "\n";
Sleep(20);
// Send an initial buffer
double x = instance.hman_data.location_X;
double y = instance.hman_data.location_Y;
//following sends the doubles as char to the receiver
testx.myFloatx = x;
sendvbuf[0] = (int)testx.myCharsx[3];
sendvbuf[1] = (int)testx.myCharsx[2];
sendvbuf[2] = (int)testx.myCharsx[1];
sendvbuf[3] = (int)testx.myCharsx[0];
testy.myFloaty = y;
sendvbuf[4] = (int)testy.myCharsy[3];
sendvbuf[5] = (int)testy.myCharsy[2];
sendvbuf[6] = (int)testy.myCharsy[1];
sendvbuf[7] = (int)testy.myCharsy[0];
//changed the length of the buffer sent as it was causing problems with sending coordinates.
iResult = send(ClientSocket, sendvbuf, 8, 0);
std::cout << "X = " << x << " " << "Y = " << y << "\n";
Sleep(200);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
}
goto Start;
// shutdown the connection since we are done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(ClientSocket);
WSACleanup();
CLIENT code:
#include "Control.h"
#include "control.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
//#define DEFAULT_BUFLEN 512
#define DEFAULT_BUFLEN 5000
#define DEFAULT_PORT "27015"
#include "Components/StaticMeshComponent.h"
//Below the "unions" are called labels and these allow for the conversion of the bytes back to a numerical value i.e. coordinate
union {
float myFloatx;
unsigned char myCharsx[sizeof(float)];
} testx;
union {
float myFloaty;
unsigned char myCharsy[sizeof(float)];
} testy;
//Declaring global variables
SOCKET ClientSocket = INVALID_SOCKET;
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo* result = NULL,
* ptr = NULL,
hints;
char sendvbuf[8];
char recvbuf[8];
int iResult;
int iSendResult;
int recvbuflen = 8;
int sendvbuflen = 8;
double x;
double y;
// Sets default values
AControl::AControl()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
//Creating an instance of the Root component and allows it to be seen in the editor and game for editing e.g. scale
Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
RootComponent = Root;
//Creating and assigning the static mesh component
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
//want to connect the static mesh with the root component so the pawn component can be edited in the editor
Mesh->AttachTo(Root);
}
// Called when the game starts or when spawned
void AControl::BeginPlay()
{
//////Below has the purpose of starting up the server: -----------------------------------------------
wchar_t command[] = L"C:\\Users\\CCRT\\Documents\\UPDATED\\FINALSERVER\\FINALSERVER\\Debug\\FINALSERVER.exe";
// Start the child process.
STARTUPINFOW si{ sizeof(STARTUPINFOW) };
PROCESS_INFORMATION pi;
if (!CreateProcessW(NULL, // No module name (use command line)
command, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
std::cout<< "CreateProcess failed\n";
}
else {
std::cout << "Command success\n";
}
//Below makes the client repeatedly search for the server until it connects with it.
int connected = 0;
while (connected == 0)
{
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
//printf("WSAStartup failed with error: %d\n", iResult);
std::cout << "WSAStartup failed with error: %d\n";
//return 1;
goto finish;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo("127.0.0.1\0", DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
//printf("getaddrinfo failed with error: %d\n", iResult);
std::cout << "getaddrinfo failed with error\n";
WSACleanup();
//return 1;
goto finish;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
//printf("socket failed with error: %ld\n", WSAGetLastError());
std::cout << "socket failed with error\n";
WSACleanup();
//return 1;
goto finish;
}
// Connect to server.
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
//printf("Unable to connect to server!\n");
std::cout << "Unable to connect to server!\n";
WSACleanup();
}
else
{
connected = 1;
}
}
iResult = send(ConnectSocket, sendvbuf, (int)sendvbuflen, 0);
if (iResult == SOCKET_ERROR) {
//printf("send failed with error: %d\n", WSAGetLastError());
std::cout << "send failed with error:\n";
closesocket(ConnectSocket);
WSACleanup();
//return 1;
goto finish;
}
std::cout << "Bytes Sent " << iResult << " " << sendvbuf[1] << std::endl;
finish:;
Super::BeginPlay();
}
// Called every frame
void AControl::Tick(float DeltaTime)
{
// Following recieves the coordinates from the server:
while (recv(ConnectSocket, recvbuf, recvbuflen, MSG_PEEK) < 8) { ; }
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
//the following turns the chars recieved back into the double format (uses the labels which were declared before)
testx.myCharsx[0] = recvbuf[3];
testx.myCharsx[1] = recvbuf[2];
testx.myCharsx[2] = recvbuf[1];
testx.myCharsx[3] = recvbuf[0];
x = testx.myFloatx;
testy.myCharsy[0] = recvbuf[7];
testy.myCharsy[1] = recvbuf[6];
testy.myCharsy[2] = recvbuf[5];
testy.myCharsy[3] = recvbuf[4];
y = testy.myFloaty;
std::cout << std::endl;
FVector NewLocation = GetActorLocation();
FRotator NewRotation = GetActorRotation();
// NewLocation.X = -y is corrct way round for the HMan to control the ball.
//NewLocation.Y = -x
//IF THE USER IS NEEDING MORE ASSISTANCE THE X AND Y COORDINATES CAN BE SCALED UP BELOW BY MULTIPLYING THEM BY A HIGHER VALUE:--------------------------------------------------------------------------
NewLocation.X = -y *150000;
NewLocation.Y = -x *150000;
NewLocation.Z = 0;
NewRotation.Roll = 0;
NewRotation.Pitch = 0;
NewRotation.Yaw = 0;
SetActorLocationAndRotation(NewLocation, NewRotation, true);
//the true is added to stop the actor moving through walls.
printf("NEW Y: %f\n", NewLocation.Y);
printf("NEW X: %f\n", NewLocation.X);
}
else if (iResult == 0)
//printf("Connection closing...\n");
std::cout << "Connection closing...\n";
else {
//printf("recv failed with error: %d\n", WSAGetLastError());
std::cout << "recv failed with error:\n";
closesocket(ClientSocket);
WSACleanup();
//return 1;
goto finish;
}
finish:;
Super::Tick(DeltaTime);
}
Thanks for any help.
I want to send random trigger signals (A and B) from Matlab to a C++ Code. The point where I stuck now is, that whenever I am not sending this trigger signal/message, the C++ Code keeps waiting for it and doesn't continue its process.
How can I make the C++ Code keep running (to collect data) without waiting for the next trigger message. Because now only once it receives the message (UDP transfers trigger signal) it gives me the specific outcome.
----------- BEGIN MATLAB CODE ---------------------
send_trigger_signal = instrfind('Type', 'udp', 'LocalHost', '127.0.0.1','RemoteHost', '192.168.0.100', 'RemotePort', 8888, 'LocalPort', 8844, 'Tag', '');
% Create the udp object if it does not exist otherwise use the object that was found.
if isempty(send_trigger_signal)
send_trigger_signal = udp('127.0.0.1', 'RemotePort', 8888, 'LocalPort', 8844);
else
fclose(send_trigger_signal);
send_trigger_signal = send_trigger_signal(1);
end
send_trigger_signal.DatagramTerminateMode='off';
send_trigger_signal.Timeout=0.0001;
send_trigger_signal.Timerperiod=0.01;
%send_trigger_signal.
% Connect to instrument object, send_trigger_signal.
fopen(send_trigger_signal);
% Communicating with instrument object, send_trigger_signal.
on_trigger_command=typecast(swapbytes(uint16([1 1 0 0])),'uint8'); %trigger on
off_trigger_command=typecast(swapbytes(uint16([0 0 0 0])),'uint8'); %trigger off
while(true)
for i=1:1
fprintf(send_trigger_signal, 'A');
WaitSecs(5);
end
end
fclose(send_trigger_signal);
send_trigger_signal=instrfindall;
delete(send_trigger_signal);
instrfindall;
----------- END MATLAB CODE ---------------------
This is the C++ code which should receive the random trigger signals from Matlab (A and B), while collecting gyro data between those signals.
To test it here the message is send every 5sec. The problem is that I cannot collect the gyro data in within those 5sec. The UDP communication is interrupting the data collection - because it is waiting those 5sec.
----------- START C++ CODE ---------------------
#include <iostream>
#include <winsock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib") // Winsock Library
#pragma warning(disable:4996)
#define BUFLEN 512
#define PORT 8888
int receiver(void)
{
int value = 5;
system("title UDP Server");
sockaddr_in server, client;
// initialise winsock
WSADATA wsa;
printf("Initialising Winsock...");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
printf("Failed. Error Code: %d", WSAGetLastError());
exit(0);
}
printf("Initialised.\n");
// create a socket
SOCKET server_socket;
if ((server_socket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
{
printf("Could not create socket: %d", WSAGetLastError());
}
printf("Socket created.\n");
// prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
// bind
if (bind(server_socket, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code: %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
puts("Bind done.");
while (true)
{
printf("Waiting for data...");
fflush(stdout);
char message[BUFLEN] = {};
// try to receive some data, this is a blocking call
int message_len;
int slen = sizeof(sockaddr_in);
if (message_len = recvfrom(server_socket, message, BUFLEN, 0, (sockaddr*)&client, &slen) == SOCKET_ERROR)
{
printf(message);
printf("recvfrom() failed with error code: %d", WSAGetLastError());
exit(0);
}
if (message[0] == 'A')
{
value = 6;
break;
}
if (message[0] == 'B')
{
value = 7;
break;
}
// print details of the client/peer and the data received
printf("Received packet from %s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
printf("Data: %s\n", message);
return 0;
}
closesocket(server_socket);
WSACleanup();
return value;
}
int main()
{
while (true)
{
// Reading some gyro data here
// Listening UDP
receiver();
}
return 0;
}
----------- END C++ CODE ---------------------
With a few structural tweaks:
Using non-blocking socket.
You don't want to restart winsock and rebind the socket every time you read from it, so that's spun off to different functions (an RAII wrapper class in the case of winsock).
C-style IO replaced with C++ IO.
exit(0) means the program succeeded, but was used in many cases where failure occurred. Consistently using exit(EXIT_FAILURE);. Might be worth throwing an exception, but it's annoying to get the error code into the exception text.
Removed some of the output because it would be spammed out now that the receive function can immediately return .
Your program could look something like this:
#include <iostream>
#include <winsock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib") // Winsock Library
#pragma warning(disable:4996)
// using modern C++ constants
constexpr int BUFLEN = 512;
constexpr int PORT = 8888;
//RAII wrapper to make sure winsock is created and disposed of responsibly
struct winsock_RAII
{
winsock_RAII()
{
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
std::cerr << "Failed to initialize winsock. Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
}
~winsock_RAII()
{
WSACleanup(); // what are we gonna do if it fails? Not much we can do.
}
};
//socket initialization
SOCKET init_sock()
{
SOCKET server_socket;
if ((server_socket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
{
std::cerr << "Failed to get socket. Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
u_long iMode = 1;
//setr socket non-blocking
if (ioctlsocket(server_socket, FIONBIO, &iMode) != NO_ERROR)
{
std::cerr << "Failed to get socket. Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
// prepare the sockaddr_in structure
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
// bind
if (bind(server_socket, (sockaddr*) &server, sizeof(server)) == SOCKET_ERROR)
{
std::cerr << "Bind failed. Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
return server_socket;
}
// read from socket
int receiver(SOCKET server_socket)
{
// try to receive some data, this is a non-blocking call
int slen = sizeof(sockaddr_in);
sockaddr_in client;
char message[BUFLEN + 1]; // no need to clear the whole buffer. We'll know
// exactly where to put the null thanks to message_len
// +1 makes sure we have room for terminator
int message_len = recvfrom(server_socket, message,
BUFLEN,
0,
(sockaddr*) &client,
&slen);
int value = 5;
if (message_len != SOCKET_ERROR)
{
message[message_len] = '\0'; // place terrminator
if (message[0] == 'A')
{
value = 6;
}
if (message[0] == 'B')
{
value = 7;
}
// print details of the client/peer and the data received
std::cout << "Received packet from " << inet_ntoa(client.sin_addr) << ':' << ntohs(client.sin_port) << '\n'
<< "Data: " << message << '\n';
}
else if (WSAGetLastError() != WSAEWOULDBLOCK)
{
// printf(message); no point to printing message. There isn't one
std::cerr << "recvfrom() failed . Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
return value;
}
int main()
{
winsock_RAII winsock; // scoped winsock initializer
SOCKET server_socket = init_sock();
while (true)
{
// Reading some gyro data here
receiver(server_socket);
}
closesocket(server_socket);
return 0;
}
You might want to use select with a short timeout to throttle the loop because it can be a serious and unnecessary CPU-eater if the gyro reading code is also quick.
I am new for C++. I tried to write a UDP client and server in C++. The server can receive data from client. But the client can not receive data from server. No matter what data the server sends, the method recvfrom in client always returns 0.
The client code is below:
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#define BUFFER_SIZE 1024
int main()
{
SOCKET sock_Client;
WSADATA WSAData;
char receBuf[BUFFER_SIZE];
char sendBuf[BUFFER_SIZE];
if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
{
printf("initialation fails!");
return -1;
}
sock_Client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
SOCKADDR_IN addr_server;
addr_server.sin_family = AF_INET;
addr_server.sin_port = htons(4567);
addr_server.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
SOCKADDR_IN sock;
int len = sizeof(sock);
while (true)
{
cout << "input data to send:";
cin >> sendBuf;
sendto(sock_Client, sendBuf, strlen(sendBuf), 0, (SOCKADDR*)&addr_server, sizeof(SOCKADDR));
//int last=recv(sock_Client, receBuf, strlen(receBuf), 0); //
int last = recvfrom(sock_Client, receBuf, strlen(receBuf), 0, (SOCKADDR*)&sock, &len);
if (last > 0)
{
receBuf[last] = '\0';
if (strcmp(receBuf, "bye") == 0)
{
cout << "server stops talking..." << endl;
closesocket(sock_Client);
break;
}
else
{
printf("received data:%s\n", receBuf);
}
}
}
closesocket(sock_Client);
WSACleanup();
return 0;
}
The server code:
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#define BUFFER_SIZE 1024
int main()
{
WSADATA WSAData;
char receBuf[BUFFER_SIZE];
char Response[BUFFER_SIZE];
if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
{
printf("initialation fails!");
exit(1);
}
SOCKET sockServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockServer == INVALID_SOCKET)
{
printf("Failed socket() \n");
return 0;
}
SOCKADDR_IN addr_Server;
addr_Server.sin_family = AF_INET;
addr_Server.sin_port = htons(4567);
addr_Server.sin_addr.S_un.S_addr = INADDR_ANY;
if (bind(sockServer, (SOCKADDR*)&addr_Server, sizeof(addr_Server)) == SOCKET_ERROR)
{
printf("Failed socket() %d \n", WSAGetLastError());
return 0;
}
SOCKADDR_IN addr_Clt;
int fromlen = sizeof(SOCKADDR);
while (true)
{
int last = recvfrom(sockServer, receBuf, 1024, 0, (SOCKADDR*)&addr_Clt, &fromlen);
if (last > 0)
{
receBuf[last] = '\0';
if (strcmp(receBuf, "bye") == 0)
{
cout << " client stop talking..." << endl;
closesocket(sockServer);
return 0;
}
else
{
printf("received data(%s):%s\n", inet_ntoa(addr_Clt.sin_addr), receBuf);
}
}
cout << "anser client:";//<br>Response = “”;
cin >> Response;
sendto(sockServer, Response, strlen(Response), 0, (SOCKADDR*)&addr_Clt, sizeof(SOCKADDR));
}
closesocket(sockServer);
WSACleanup();
return 0;
}
Anyone know what is wrong with the code?
The code runs in Windows. So, set(CMAKE_CXX_STANDARD 14) has to be added into CMakeLists.txt. If you want to run the code, please notice that.
I have adapted the code from http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html (selectserver.c -- a cheezy multiperson chat server) to compile on Windows. The complete code follows below. I compile using gcc version 6.1.0 (x86_64-posix-seh, Built by MinGW-W64 project). I compile using gcc6.1.0 on Linux, too.
Basically, you run it, telnet 2 or more times to port 9034, and whatever you type in one telnet session gets echoed to the other telnet sessions (depending on the system, one has to type Enter before it gets echoed - on Windows it echoes every character typed).
Now the problem :
On Linux AMD64 or ARM, I can connect to it from localhost and from another system, be that Windoes or Linux. On Windows, it only works on localhost, and I fail to understand why. The fact that hints.ai_flags = AI_PASSIVE; is specified makes it listen on all interfaces, if I understand things correctly.
The MSDN doc states:
Setting the AI_PASSIVE flag indicates the caller intends to use the returned socket address structure in a call to the bind function.
When the AI_PASSIVE flag is set and pNodeName is a NULL pointer, the IP address portion of the socket address structure is set to INADDR_ANY for IPv4 addresses and IN6ADDR_ANY_INIT for IPv6 addresses.
The code reads :
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0)
How do I make this behave correctly on Windows?
It is compiled with :
g++ -O0 -g3 -Wall -c -fmessage-length=0 -o "src\chatserver.o" "..\src\chatserver.cpp"
and linked with
g++ -mwindows -o chatserver.exe "src\chatserver.o" -lws2_32
What do I need to change in the code please?
This is the complete code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#ifdef __linux__
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
#ifdef _WIN32
#include <ws2tcpip.h>
#endif
#define PORT "9034" // port we're listening on
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) { return &(((struct sockaddr_in*)sa)->sin_addr); }
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
#ifdef _WIN32
WSADATA wsaData; // Initialize Winsock
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (NO_ERROR != nResult) {
printf ("Error occurred while executing WSAStartup().");
}
#endif
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
int fdmax; // maximum file descriptor number
int listener; // listening socket descriptor
int newfd; // newly accept()ed socket descriptor
struct sockaddr_storage remoteaddr; // client address
socklen_t addrlen;
char buf[256]; // buffer for client data
int nbytes;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1; // for setsockopt() SO_REUSEADDR, below
int i, j, rv;
struct addrinfo hints, *ai, *p;
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
// get us a socket and bind it
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "selectserver: %s\n", gai_strerror(rv));
exit(1);
}
for(p = ai; p != NULL; p = p->ai_next) {
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) { continue; }
// lose the pesky "address already in use" error message
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(int));
//setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, "1", sizeof(int));
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}
break;
}
// if we got here, it means we didn't get bound
if (p == NULL) {
fprintf(stderr, "selectserver: failed to bind\n");
exit(2);
}
freeaddrinfo(ai); // all done with this
// listen
if (listen(listener, 10) == -1) {
perror("listen");
exit(3);
}
// add the listener to the master set
FD_SET(listener, &master);
// keep track of the biggest file descriptor
fdmax = listener; // so far, it's this one
// main loop
for(;;) {
read_fds = master; // copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
// run through the existing connections looking for data to read
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) { // we got one!!
if (i == listener) {
// handle new connections
addrlen = sizeof remoteaddr;
newfd = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);
if (newfd == -1) {
perror("accept");
}
else {
FD_SET(newfd, &master); // add to master set
if (newfd > fdmax) { // keep track of the max
fdmax = newfd;
}
std::cout << "selectserver: new connection on socket " << newfd;
/*
printf("selectserver: new connection from %s on "
"socket %d\n",
inet_ntop(remoteaddr.ss_family,get_in_addr((struct sockaddr*)&remoteaddr),remoteIP, INET6_ADDRSTRLEN),newfd);
*/
}
}
else {
// handle data from a client
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
// got error or connection closed by client
if (nbytes == 0) {
// connection closed
std::cout << "selectserver: socket " << i << " hung up";
}
else {
perror("recv");
}
close(i); // bye!
FD_CLR(i, &master); // remove from master set
}
else {
// we got some data from a client
for(j = 0; j <= fdmax; j++) {
// send to everyone!
if (FD_ISSET(j, &master)) {
// except the listener and ourselves
if (j != listener && j != i) {
if (send(j, buf, nbytes, 0) == -1) {
perror("send");
}
}
}
}
}
} // END handle data from client
} // END got new incoming connection
} // END looping through file descriptors
} // END for(;;)--and you thought it would never end!
return 0;
}
getaddrinfo() can return multiple IP addresses. You are correctly looping through all of the returned addresses, but you are breaking the loop after the first successful bind(), and then you are calling listen() on that one single socket, regardless of its socket family. Since you are using AF_UNSPEC when calling getaddrinfo(), it is possible that it is returning BOTH INADDR_ANY for IPv4 AND IN6ADDR_ANY_INIT for IPv6.
Change your code to listen on every IP address that getaddrinfo() returns, and to keep track of those sockets so you can use all of them in your select() loop. If you just wanted to listen on either INADDR_ANY or IN6ADDR_ANY_INIT, there would be no point in using getaddrinfo() at all, as you could just hard-code the socket()/bind() calls for those two addresses and get rid of the loop altogether. The purpose of using getaddrinfo() in this manner is to let it decide what you should be listening on, given the AI_PASSIVE hint you provided. Don't make assumptions about its output.
You also cannot use fdmax on Windows, so you need to re-write your select() loop. Sockets on Windows do not use file descriptors, so you can't simply loop from 0 <= fdmax when calling FD_ISSET(), and the first parameter of select() is ignored as well. I suggest not storing your active socket descriptors/handles in a master fd_set to begin with. Use a std::list or other suitable container instead, and then dynamically create a new fd_set whenever you need to call select(). This would be more portable across different platforms.
Try something more like this:
#include <unistd.h>
#include <sys/types.h>
#ifdef __linux__
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define SOCKET int
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1
inline int closesocket(int s) { return close(s); }
inline int getLastSocketError() { return errno; }
#endif
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
inline int getLastSocketError() { return WSAGetLastError(); }
#endif
#include <iostream>
#include <list>
#include <algorithm>
#include <utility>
#define PORT "9034" // port we're listening on
#ifdef _WIN32
#define SELECT_MAXFD 0
#else
#define SELECT_MAXFD fdmax+1
#endif
enum eSocketType { stListener, stClient };
struct SocketInfo
{
SOCKET sckt;
eSocketType type;
};
SocketInfo makeSocketInfo(SOCKET sckt, eSocketType type) {
SocketInfo info;
info.sckt = sckt;
info.type = type;
return info;
}
// get sockaddr, IPv4 or IPv6:
void* get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
std::list<SocketInfo> master; // socket descriptors
std::list<SocketInfo>::iterator i, j;
SOCKET sckt, newsckt; // socket descriptors
fd_set read_fds; // temp file descriptor list for select()
#ifndef _WIN32
int fdmax; // maximum file descriptor number
#endif
struct sockaddr_storage remoteaddr; // client address
socklen_t addrlen;
char buf[256]; // buffer for client data
int nbytes;
char ipAddr[INET6_ADDRSTRLEN];
int yes = 1; // for setsockopt() SO_REUSEADDR, below
int rv;
struct addrinfo hints, *ai, *p;
#ifdef _WIN32
WSADATA wsaData; // Initialize Winsock
rv = WSAStartup(MAKEWORD(2,2), &wsaData);
if (NO_ERROR != rv) {
std::cerr << "WSA startup failed, error: " << rv << std::endl;
return 1;
}
#endif
// get us the listening sockets and bind them
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
rv = getaddrinfo(NULL, PORT, &hints, &ai);
if (rv != 0) {
std::cerr << "selectserver: getaddrinfo failed, error: " << gai_strerror(rv) << std::endl;
return 2;
}
for(p = ai; p != NULL; p = p->ai_next) {
sckt = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (INVALID_SOCKET == sckt) {
std::cerr << "selectserver: socket failed, error: " << getLastSocketError() << std::endl;
continue;
}
// lose the pesky "address already in use" error message
setsockopt(sckt, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(int));
//setsockopt(sckt, SOL_SOCKET, SO_REUSEADDR, "1", sizeof(int));
if (bind(sckt, p->ai_addr, p->ai_addrlen) < 0) {
std::cerr << "selectserver: bind failed, error: " << getLastSocketError() << std::endl;
closesocket(sckt);
continue;
}
// listen
if (listen(sckt, 10) < 0) {
std::cerr << "selectserver: listen failed, error: " << getLastSocketError() << std::endl;
closesocket(sckt);
continue;
}
/*
std::cout << "selectserver: listening on IP " << inet_ntop(p->ai_family, get_in_addr(p->ai_addr), ipAddr, sizeof(ipAddr)) << ", socket " << sckt << std::endl,
*/
// add the listener to the master list
master.push_back(makeSocketInfo(sckt, stListener));
}
freeaddrinfo(ai); // all done with this
// if we got here, it means we didn't get bound
if (master.empty()) {
std::cerr << "selectserver: failed to bind" << std::endl;
return 3;
}
// main loop
while (1) {
#ifndef _WIN32
fdmax = 0;
#endif
FD_ZERO(&read_fds);
for (i = master.begin(); i != master.end(); ++i) {
sckt = i->sckt;
FD_SET(sckt, &read_fds);
#ifndef _WIN32
fdmax = std::max(fdmax, sckt);
#endif
}
if (select(SELECT_MAXFD, &read_fds, NULL, NULL, NULL) < 0) {
std::cerr << "select failed, error: " << getLastSocketError() << std::endl;
return 4;
}
// run through the existing connections looking for data to read
for(i = master.begin(); i != master.end(); ) {
sckt = i->sckt;
if (!FD_ISSET(sckt, &read_fds)) {
++i;
continue;
}
// we got one!!
if (stListener == i->type) {
// handle a new connection
addrlen = sizeof(remoteaddr);
newsckt = accept(sckt, (struct sockaddr *)&remoteaddr, &addrlen);
if (INVALID_SOCKET == newsckt) {
std::cerr << "accept failed on socket " << sckt << ", error: " << getLastSocketError() << std::endl;
}
else {
master.push_back(makeSocketInfo(newsckt, stClient)); // add to master list
std::cout << "selectserver: new connection, socket " << newsckt << std::endl;
/*
std::cout << "selectserver: new connection from " << inet_ntop(remoteaddr.ss_family, get_in_addr((struct sockaddr*)&remoteaddr), ipAddr, sizeof(ipAddr)) << ", socket " << newsckt << std::endl,
*/
}
}
else {
// handle data from a client
nbytes = recv(sckt, buf, sizeof(buf), 0);
if (nbytes <= 0) {
// got error or connection closed by client
if (nbytes == 0) {
// connection closed
std::cout << "selectserver: socket " << sckt << " disconnected" << std::endl;
}
else {
std::cerr << "selectserver: recv failed on socket " << sckt << ", error: " << getLastSocketError() << std::endl;
}
closesocket(sckt); // bye!
i = master.erase(i); // remove from master list
continue;
}
// send to everyone!
// except a listener and ourselves
for(j = master.begin(); j != master.end(); ) {
if ((j->sckt != sckt) && (stClient == j->type)) {
if (send(j->sckt, buf, nbytes, 0) < 0) {
std::cerr << "selectserver: send failed on socket " << j->sckt << ", error: " << getLastSocketError() << std::endl;
closesocket(j->sckt); // bye!
j = master.erase(j); // remove from master list
continue;
}
}
++j;
}
}
++i;
}
}
for(i = master.begin(); i != master.end(); ++i) {
closesocket(i->sckt);
}
#ifdef _WIN32
WSACleanup();
#endif
return 0;
}
If you are running the code on a system that supports dual-stack sockets (like Windows), you can change AF_UNSPEC to AF_INET6 (or just hard-code socket()/bind() without using getaddrinfo()) to create only IPv6 listener(s) on IN6ADDR_ANY_INIT, and then disable the IPV6_V6ONLY socket option on them. This will allow IPv6 listen sockets to accept both IPv4 and IPv6 clients, reducing the number of listen sockets you need to create.
Communication between a server and a clients works, but the server don't forward the client messages to the other connected client's, but only to the sender.
i want the server react to incoming messages by broadcasting them to all clients like a chat system, but keep my command system without sharring it with all clients, but with with sender.
down below is the sources:
server
/*server*/
#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <string>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <process.h>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define PORT "3490"
#define SERVER "localhost"
#include <time.h>
WSADATA wsa;
SOCKET s , new_socket;
struct sockaddr_in server , client;
int c;
char *message;
std::string line;
DWORD WINAPI ProcessClient (LPVOID lpParameter)
{
SOCKET AcceptSocket = (SOCKET) lpParameter;
// Send and receive data.
int bytesSent;
int bytesRecv = SOCKET_ERROR;
char sendbuf[2000]="";
char sendbuf2[2000]="";
char recvbuf[2000]="";
char timebuf[128];
sprintf(sendbuf, "Hello, it's a test server at %s:%d (commands: 1, 2, exit)\n", SERVER, PORT);
bytesSent = send( AcceptSocket, sendbuf, strlen(sendbuf), 0);
if (bytesSent == SOCKET_ERROR)
{
printf( "Error at send hello: %ld\n", WSAGetLastError());
goto fin;
}
while (1)
{
_strtime( timebuf );
ZeroMemory (recvbuf, sizeof(recvbuf));
bytesRecv = recv( AcceptSocket, recvbuf, 32, 0);
printf( "%s Client said: %s\n", timebuf, recvbuf);
sprintf(sendbuf, "%s Client said: %s\n", timebuf, recvbuf);
bytesSent = send( AcceptSocket, sendbuf, strlen(sendbuf), 0);
if (strcmp(recvbuf, "1") == 0)
{
sprintf(sendbuf, "You typed ONE\n");
//printf("Sent '%s'\n", sendbuf);
bytesSent = send( AcceptSocket, sendbuf, strlen(sendbuf), 0);
if (bytesSent == SOCKET_ERROR)
{
printf( "Error at send: %ld\n", WSAGetLastError());
goto fin;
}
}
else if (strcmp(recvbuf, "2") == 0)
{
sprintf(sendbuf, "You typed TWO\n");
//printf("Sent '%s'\n", sendbuf);
bytesSent = send( AcceptSocket, sendbuf, strlen(sendbuf), 0);
if (bytesSent == SOCKET_ERROR)
{
printf( "Error at send: %ld\n", WSAGetLastError());
goto fin;
}
}
else if (strcmp(recvbuf, "exit") == 0)
{
printf( "Client has logged out\n", WSAGetLastError());
goto fin;
}
else
{
// sprintf(sendbuf, "unknown command\n");
//printf("Sent '%s'\n", sendbuf);
// bytesSent = send( AcceptSocket, sendbuf, strlen(sendbuf), 0);
if (bytesSent == SOCKET_ERROR)
{
// printf( "Error at send: %ld\n", WSAGetLastError());
goto fin;
}
}
}
fin:
printf("Client processed\n");
closesocket(AcceptSocket);
return 0;
}
int main(int argc , char *argv[])
{
std::cout << ("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
std::cout << ("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
std::cout << ("Could not create socket : %d" , WSAGetLastError());
}
std::cout << ("Socket created.\n");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 3490 );
//Bind
if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
std::cout << ("Bind failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
puts("Bind done");
//Listen to incoming connections
listen(s , 3);
//Accept and incoming connection
std::cout << ("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
while(true){
while((new_socket = accept(s , (struct sockaddr *)&client, &c)) != INVALID_SOCKET) {
// Create a new thread for the accepted client (also pass the accepted client socket).
printf( "Client Connected.\n");
DWORD dwThreadId;
CreateThread (NULL, 0, ProcessClient, (LPVOID) new_socket, 0, &dwThreadId);
}
}
if (new_socket == INVALID_SOCKET)
{
std::cout << ("accept failed with error code : %d" , WSAGetLastError());
return 1;
}
closesocket(s);
WSACleanup();
return 0;
}
client
/*client*/
#define WIN32_LEAN_AND_MEAN
#pragma comment(lib,"ws2_32.lib")
#include <iostream>
#include <process.h>
#include <string>
#include <winsock2.h>
SOCKET Socket;
#define SERVER "localhost"
int PORT = 3490;
std::string line;
bool chat = false;
class Buffer
{
public:
int ID;
char Message[256];
}sbuffer;
int ClientThread()
{
char buffer[2000]= "";
for(;; Sleep(10))
{
if(recv(Socket, buffer, sizeof(sbuffer), NULL)!=SOCKET_ERROR)
{
strncpy(sbuffer.Message, buffer, sizeof(sbuffer.Message));
std::cout << "<Client:" << sbuffer.ID << ":> " << sbuffer.Message <<std::endl;
ZeroMemory (buffer, sizeof(buffer));
}
}
return 0;
}
int main(void)
{
WSADATA WsaDat;
if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0)
{
std::cout<<"Winsock error - Winsock initialization failed\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
// Create our socket
Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(Socket==INVALID_SOCKET)
{
std::cout<<"Winsock error - Socket creation Failed!\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
// Resolve IP address for hostname
struct hostent *host;
if((host=gethostbyname(SERVER))==NULL)
{
std::cout<<"Failed to resolve hostname.\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
// Setup our socket address structure
SOCKADDR_IN SockAddr;
SockAddr.sin_port=htons(PORT);
SockAddr.sin_family=AF_INET;
SockAddr.sin_addr.s_addr=*((unsigned long*)host->h_addr);
// Attempt to connect to server
if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr))!=0)
{
std::cout<<"Failed to establish connection with server\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
// If iMode!=0, non-blocking mode is enabled.
u_long iMode=1;
ioctlsocket(Socket,FIONBIO,&iMode);
// Main loop
for(;;)
{
// Display message from server
char buffer[1000];
memset(buffer,0,999);
int inDataLength=recv(Socket,buffer,1000,0);
std::cout<<buffer;
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE) ClientThread, NULL, NULL, NULL);
for(;; Sleep(10))
{
std::string buffer;
std::getline(std::cin, buffer);
if (send(Socket, buffer.c_str(), buffer.length(), NULL) < 1){
}
}
int nError=WSAGetLastError();
if(nError!=WSAEWOULDBLOCK&&nError!=0)
{
std::cout<<"Winsock error code: "<<nError<<"\r\n";
std::cout<<"Server disconnected!\r\n";
// Shutdown our socket
shutdown(Socket,SD_SEND);
// Close our socket entirely
closesocket(Socket);
break;
}
Sleep(1000);
}
WSACleanup();
system("PAUSE");
return 0;
}
Please help me fix it, i'm new into socket's. Show me how to do as i'm going understand better with code and it will also be usefull to others who might need it in the future.
If you need the server to communicate with multiple clients, then you need some kind of collection of all the connected clients. Then it's easy to send to all connections, or send to all connection but the originating connection.
How to do it will differ vastly between C and C++, but for C++ look into structures and std::vector.
In pseudo-code it would be something like this:
while (run_server)
{
poll_all_connections();
if (have_new_connection())
{
accept_new_connection();
add_connection_in_collection();
}
else
{
for (connection in all_connections())
{
if (have_input(connection))
{
input = read_from_connection(connection);
for (send_to in all_connections())
write_to_connection(connection, input)
}
}
}
}
If you implement the above pseudo-code, then input from any connection will be sent to all connections.
Don't forget to remove a connection from the collection if the connection is broken (error or disconnect.)
You have to maintain a list of all the client socket connections then send the data to each client one by one.
or you can use threading to implement this as follows :-
Server-thread()
{
while(true)
{
/// Accept Connection in ClientSocket.
HandleClient-Thread(ClientSocket) ; // launch a thread for each client .
}
}
HandleClient-Thread(ClientSocket)
{
// handle this client here
}