So I've been creating a winsock server/client in UE4. I can get the client to connect to the server however once the client sends the first message it seems to close the socket, preventing any further messages to be sent to the server. It also seems like the server is doing the same thing when sending data.
client
// Convert IP & port to standard lib
const std::string IP = std::string(TCHAR_TO_UTF8((*GameInstance->GetIPAddress())));
const std::string PORT = std::string(TCHAR_TO_UTF8(*GameInstance->GetPort()));
// Set the version of WSA we are using
auto Version = MAKEWORD(2, 2);
WSAData WSData;
struct addrinfo* Result = nullptr, * ptr = nullptr, hints;
int iResult; // Store Initializing results
std::string message; // Define a message to send to the server
UE_LOG(LogTemp, Log, TEXT("Starting Client"));
// Initialize WinSock
iResult = WSAStartup(Version, &WSData); // Start winsock
if(iResult != 0)
{
UE_LOG(LogTemp, Error, TEXT("Failed to initialize winsock"));
return ECreateConnectionFlag::WINSOCK_FAILED;
}
UE_LOG(LogTemp, Log, TEXT("Initialized WinSock"));
// Setup hints
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
UE_LOG(LogTemp, Log, TEXT("Connecting"));
// Get the address details
iResult = getaddrinfo(IP.c_str(), PORT.c_str(), &hints, &Result);
if(iResult != 0)
{
UE_LOG(LogTemp, Error, TEXT("Error getting address info from the server"));
WSACleanup();
return 0;
}
// Connect the player
for(ptr = Result; ptr != nullptr; ptr->ai_next)
{
GameInstance->SetPlayerSocket(socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol));
if(GameInstance->GetLoggedInPlayer().PlayerSocket == INVALID_SOCKET)
{
UE_LOG(LogTemp, Error, TEXT("Failed to create socket"));
WSACleanup();
return 0;
}
iResult = connect(GameInstance->GetLoggedInPlayer().PlayerSocket, ptr->ai_addr, ptr->ai_addrlen);
if(iResult == SOCKET_ERROR)
{
closesocket(GameInstance->GetLoggedInPlayer().PlayerSocket);
GameInstance->SetPlayerSocket(INVALID_SOCKET);
continue;
}
break;
}
freeaddrinfo(Result); // Release Address information as it's no longer required
// Ensure the socket is valid
if(GameInstance->GetLoggedInPlayer().PlayerSocket == INVALID_SOCKET)
{
UE_LOG(LogTemp, Error, TEXT("Unable to connect to server..."));
WSACleanup();
return 0;
}
// WE ARE CONNECTED
/* CONNECT AND SEND USERNAME */
FString SignInMessage = FString("Username-" + GameInstance->GetLoggedInPlayer().Username);
std::string ConnectionMessage = std::string(TCHAR_TO_UTF8(*SignInMessage));
iResult = send(GameInstance->GetLoggedInPlayer().PlayerSocket, ConnectionMessage.c_str(), (int)strlen(ConnectionMessage.c_str()), 0);
if(iResult <= 0)
{
int error = WSAGetLastError();
UE_LOG(LogTemp, Error, TEXT("Failed to send message: %d"), error);
return 0;
}
while(bRunThread)
{
UE_LOG(LogTemp, Log, TEXT("Receiving Data"));
/* DISCONNECT FROM SERVER */
const std::string msg = "Hello World";
iResult = send(GameInstance->GetLoggedInPlayer().PlayerSocket, msg.c_str(), (int)strlen(msg.c_str()), 0);
if(iResult <= 0)
{
int error = WSAGetLastError();
UE_LOG(LogTemp, Error, TEXT("Failed to send message: %d"), error);
return 0;
}
FPlatformProcess::Sleep(1.0f);
}
/* DISCONNECT FROM SERVER */
const std::string DisconnectMsg = "Disconnect";
iResult = send(GameInstance->GetLoggedInPlayer().PlayerSocket, DisconnectMsg.c_str(), (int)strlen(DisconnectMsg.c_str()), 0);
if(iResult <= 0)
{
int error = WSAGetLastError();
UE_LOG(LogTemp, Error, TEXT("Failed to send message: %d"), error);
return 0;
}
UE_LOG(LogTemp, Warning, TEXT("Client Disconnected"));
closesocket(GameInstance->GetLoggedInPlayer().PlayerSocket);
WSACleanup();
return 0;
}
server
WSAData wsa;
struct addrinfo hints; // Server Hint details
struct addrinfo* server = NULL; // Address info of the server
SOCKET serverSocket = INVALID_SOCKET; // Server Listening Socket
PlayerArray* Players = new PlayerArray(); // Reference to all the players in the server
LobbyArray* Lobbies = new LobbyArray(); // Reference to all the lobbies in the server
// Initialize the winsock library
std::cout << "Initializing WinSock..." << std::endl;
int WSA_Init = WSAStartup(MAKEWORD(2, 2), &wsa);
if (WSA_Init != 0)
{
std::cerr << "Error Initializing Winsock";
WSACleanup();
return;
}
else
{
std::cout << "Winsock Initialized" << std::endl;
}
// Setup Hints
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Setup the server
std::cout << "Setting up Server" << std::endl;
getaddrinfo(IP_ADDRESS, PORT, &hints, &server);
// Create the listening socket
std::cout << "Creating Listening socket" << std::endl;
serverSocket = socket(server->ai_family, server->ai_socktype, server->ai_protocol);
if (serverSocket == INVALID_SOCKET)
{
std::cerr << "Failed creating listening socket" << std::endl;
WSACleanup();
return;
}
else
{
std::cout << "Created listen socket" << std::endl;
}
// Set the socket to be TCP
setsockopt(serverSocket, IPPROTO_TCP, TCP_NODELAY, &OPTION_VALUE, sizeof(int));
// Bind the socket
std::cout << "Binding Socket..." << std::endl;
bind(serverSocket, server->ai_addr, (int)server->ai_addrlen);
// Start the server
std::cout << "Server has started & is listening..." << std::endl;
listen(serverSocket, SOMAXCONN);
while (true)
{
std::cout << "Players Connected: " << Players->Count() << std::endl;
SOCKET Incoming = INVALID_SOCKET; // Define a socket for anything incoming
Incoming = accept(serverSocket, NULL, NULL); // Accept the incoming message from the socket
// If the socket is not valid than continue through the loop
if (Incoming == INVALID_SOCKET)
{
std::cout << "Invalid Socket" << std::endl;
continue;
}
else
{
std::cout << "Valid Socket" << std::endl;
}
char tempmsg[DFT_BUFLEN] = ""; // Define a temp msg to store the message from the client
int received = recv(Incoming, tempmsg, DFT_BUFLEN, 0); // Receive a message from the client
std::string convertedMessage = tempmsg;
// Check that the received message is from a valid socket
if (received != SOCKET_ERROR)
{
std::string message = tempmsg; // Assing the temp message to a string to split
if (convertedMessage == "Disconnect")
{
Players->RemovePlayer(Incoming);
std::cout << "Player Disconnected..." << std::endl;
continue;
}
else
{
std::cout << tempmsg << std::endl; // === DEBUG ===
// Split the string
char* next_split;
char* split_string = strtok_s(tempmsg, "-", &next_split);
std::string FirstMsg = split_string;
if (FirstMsg == "Username")
{
std::cout << next_split << " Has joined the server" << std::endl; // Server message
// Get the player that we want to set the username to
// Create the player and add it to the server list
Player* NewPlayer = new Player();
Players->AddPlayer(NewPlayer);
NewPlayer->SetUsername(next_split); // Set the usernames
continue;
}
else if (split_string == "Lobby")
{
if (next_split == "Create")
{
Lobby* NewLobby = Lobbies->CreateLobby(); // Create a new lobby
Player* SocketPlayer = Players->GetPlayerBySocket(Incoming); // Get the player creating it by socket
// ensure that the player is valid, if so add the player to the lobby
// Otherwise send an error message to the console.
if (SocketPlayer != nullptr)
{
NewLobby->AddPlayerToLobby(SocketPlayer);
}
else
{
std::cerr << "Failed Locate player to add to lobby" << std::endl;
}
}
else if (next_split == "Destroy")
{
// TODO: Destroy Specific lobby
}
continue;
}
else
{
std::cout << "Error Reading Message" << std::endl;
}
}
}
else
{
std::cerr << "Socket Error when recieving message" << std::endl;
}
}
// Clean up the server
delete Players;
delete Lobbies;
closesocket(serverSocket);
WSACleanup();
return;
Console output after disconnecting
You are making a fundamental TCP mistake. TCP is a stream protocol., its only gurantees are
the bytes you send will be received in the same order they were sent
they will be received only once
BUT there are no 'messages' or 'records' in TCP. You can send a 100 byte message and the other end can receive
one 100 byte message
25 4 byte messages
100 1 byte messages
one 25, one 12, one 3, and one 60 (hope my math is correct)
So in the receive logic you must do this
char buffer[1000]; // or whatever
int length = ????;
char* bptr = buffer;
while(length > 0){
int recvLen = recv(sock, bptr, length,0);
if (recvLen < 1){
// error - disconnect or other failure
break;
}
bptr += recvLen;
length -= recvLen;
}
Ie keep pulling data till you have the whole message
BUT this means you need to know the messages length in advance. So either
send a well known sized length first
send fixed length messages
Or you can have a recognizable termination sequence- ie 10 byte of FF means end of message (see crlfcrlf at end of HTTP get for example)
The first option is the most robust (send length then data)
Related
I want to create two projects with this code so that they can chat with each other, but no matter how much I send, the data does not reach the other client.
I've been thinking and trying for hours on this problem, but it doesn't work. Various multicast chat programs on the web are written in languages other than C++, some use threads and some do not. To the best of my knowledge right now, I can't understand the codes on the web.
For fear of lengthy code, the basic header file and error output function have been omitted.
// header file and function declaration
#define MAXBUF 80
SOCKADDR_IN maddr;
int main(int argc, char* argv[]) {
int port;
cout << "input port number" << endl;
cin >> port;
cout << "use port : " << port << endl;
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa))
{
err_display("WSAStartup");
return -1;
}
//create send socket
SOCKET r_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (r_sock == INVALID_SOCKET)
{
err_display(" recv socket");
return -1;
}
//create recv socket
SOCKET s_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s_sock == INVALID_SOCKET)
{
err_display(" send socket");
return -1;
}
// bind
maddr.sin_family = AF_INET;
maddr.sin_port = htons(port);
maddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(r_sock, (SOCKADDR*)&maddr, sizeof(maddr))) {
err_display("bind");
return -1;
}
// Join the Multicast address
const char* mip = "236.0.0.1";
IP_MREQ mreq;
mreq.imr_interface.s_addr = htonl(INADDR_ANY); // s_addr = 주소
// Setting Multicast address
if (!(inet_pton(AF_INET, mip, &mreq.imr_multiaddr))) {
err_display("inet_pton");
return -1;
}
// JOIN
if (setsockopt(r_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq))) {
err_display("setsockopt");
return -1;
}
while (true) {
HANDLE h1 = (HANDLE)_beginthreadex(NULL, 0, &sendf, (LPVOID)s_sock, 0, NULL);
HANDLE h2 = (HANDLE)_beginthreadex(NULL, 0, &recvf, (LPVOID)r_sock, 0, NULL);
}
closesocket(r_sock);
closesocket(s_sock);
WSACleanup();
return 0;
}
unsigned __stdcall sendf(LPVOID arg) // send thread function
{
SOCKET s_sock = (SOCKET)arg;
char mesbuf[MAXBUF];
int sendlen;
while (1)
{
// send
char mesbuf[MAXBUF];
if (fgets(mesbuf, MAXBUF - 1, stdin) == NULL)
break;
cout << "send Thread" << endl;
sendlen = strlen(mesbuf);
sendto(s_sock, mesbuf, sendlen, 0, (SOCKADDR*)&maddr, sizeof(maddr));
}
return 0;
}
unsigned __stdcall recvf(LPVOID arg) // recv thread function
{
SOCKADDR_IN paddr; // peer address
int namelen = sizeof(paddr);
SOCKET r_sock = (SOCKET)arg;
char mesbuf[MAXBUF];
int recvlen;
while (1)
{
char mesbuf[MAXBUF];
//recive
recvlen = recvfrom(r_sock, mesbuf, MAXBUF - 1, 0, (SOCKADDR*)&paddr, &namelen);
cout << "recv Thread" << endl;
if (recvlen == SOCKET_ERROR) {
err_display("recv error");
closesocket(r_sock);
break;
}
if (recvlen == 0)
{
cout << "normal close connection case" << endl;
closesocket(r_sock);
break;
}
mesbuf[recvlen] = '\0'; // string conversion
cout << "from : " << mesbuf << endl;
}
return 0;
}
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 currently trying to understand how HTTP requests work so I am using winsock2 for c++ to try and send some HTTP requests manually.
My code looks like this:
#include <iostream>
#include <SFML/Graphics.hpp>
#include "EasyWinSock.h"
char ip[] = "prnt.sc";
char port[] = "80";
int main() {
easy_win_sock ews(ip, port);
ews.init_win_sock();
ews.create_win_sock();
ews.connect_win_sock();
char sendbuf2[] = "GET /t/gh17d-1645175682/post HTTP/1.1\r\nUser-Agent: kekwtestkekw\r\nHost: ptsv2.com\r\n\r\n";
char sendbuf[] = "GET /111111 HTTP/1.1\r\nHost: www.prnt.sc\r\n\r\n";
ews.send_win_sock(sendbuf, (int)strlen(sendbuf));
DATA *result = ews.recieve_win_sock_text(512); // dynamically allocated
/*
for (int i = 0; i < result->content->size(); i++) {
std::cout << (*result->content)[i];
}
*/
ews.cleanup_win_sock();
return 0;
}
With the Winsocket tucked away in the struct:
#pragma once
#pragma comment(lib, "ws2_32.lib")
#include <iostream>
#include <vector>
#include <winsock2.h>
#include <WS2tcpip.h>
struct DATA {
std::vector<char*>* content;
int size;
};
struct easy_win_sock {
char *ip;
char *port;
WSADATA *wsaData;
addrinfo* result = nullptr;
addrinfo* ptr = nullptr;
SOCKET *sock;
easy_win_sock(char* ip, char* port) {
this->ip = ip;
this->port = port;
this->sock = new SOCKET;
this->wsaData = new WSADATA;
}
void init_win_sock() {
int i_result = WSAStartup(MAKEWORD(2, 2), wsaData);
if (i_result != 0) {
std::cout << "WASStartup failed: " << i_result << std::endl;
exit(1);
}
}
void create_win_sock() {
this->result = NULL;
this->ptr = NULL;
addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// get ip adress of hostname
int i_result = getaddrinfo(this->ip, this->port, &hints, &this->result);
if (i_result != 0) {
std::cout << "getaddrinfo failed: " << i_result << std::endl;
WSACleanup();
exit(1);
}
// create socket
*this->sock = INVALID_SOCKET;
// Attempt to connect to the first adress returned by the call to getaddrinfo
this->ptr = this->result;
// create socket for connecting to server
*this->sock = socket(this->ptr->ai_family, this->ptr->ai_socktype, this->ptr->ai_protocol);
if (*this->sock == INVALID_SOCKET) {
std::cout << "Error at socket(): " << WSAGetLastError() << std::endl;
freeaddrinfo(this->result);
WSACleanup();
exit(1);
}
}
void connect_win_sock() {
// connect to server
int i_result = connect(*this->sock, this->ptr->ai_addr, (int)this->ptr->ai_addrlen);
if (i_result == SOCKET_ERROR) {
closesocket(*this->sock);
*this->sock = INVALID_SOCKET;
}
// if connection failed we just close everithing instead of trying other adresses from getadressinfo()
freeaddrinfo(result);
if (*this->sock == INVALID_SOCKET) {
std::cout << "Unable to connect to server!" << std::endl;
WSACleanup();
exit(1);
}
}
void send_win_sock(char* data, int buf_len) {
int i_result = send(*this->sock, data, buf_len, 0);
if (i_result == SOCKET_ERROR) {
std::cout << "Send failed: " << WSAGetLastError() << std::endl;
closesocket(*this->sock);
WSACleanup();
exit(1);
}
}
DATA* recieve_win_sock_text(int buf_size) {
std::vector<char*>* recvbufs = new std::vector<char*>;
DATA* data = new DATA;
// recieve data till server closes connection
int i_result = 1; // number of recieved bytes
while (i_result > 0) {
recvbufs->push_back(new char[buf_size]);
i_result = recv(*this->sock, (*recvbufs)[recvbufs->size() - 1], buf_size - 1, 0);
if (i_result >= 0) {
(*recvbufs)[recvbufs->size() - 1][i_result] = '\0';
std::cout << (*recvbufs)[recvbufs->size() - 1];
}
else {
std::cout << "recv failed: " << WSAGetLastError() << std::endl;
}
}
data->content = recvbufs;
return data;
}
void cleanup_win_sock() {
// shutdown the connection for sending
// still can recieve
int i_result = shutdown(*this->sock, SD_SEND);
if (i_result == SOCKET_ERROR) {
std::cout << "Shutdown failed: " << WSAGetLastError() << std::endl;
closesocket(*this->sock);
WSACleanup();
exit(0);
}
closesocket(*this->sock);
WSACleanup();
delete this->sock;
delete this->wsaData;
}
};
I am using http://ptsv2.com/ to try out my HTTP requests and on this site they work. When I however try to send a GET request to the site prnt.sc/111111 I get different Error codes depending on my GET request. When I just do a
GET /111111 HTTP/1.1
Host: prnt.sc
<empty line>
for example, I get a 403 Forbidden.
When I use the Website https://reqbin.com/ to test HTTP requests and i put in prnt.sc/111111 it generates the same request but the response it shows is 200 OK.
Can anyone help me? I'm seriously stuck here.
Thanks in advance.
I am sending UDP packets to Hercules for testing, and whenever I send data it hangs Hecrcules.
I am not sure if it is an issue with my code.
Please have a look at my code and if it has any issues, please let me know.
void UDPConnect::Connect(unsigned short local_port, const char* local_addr)
{
WSADATA wsa;
int err;
err = WSAStartup(MAKEWORD(2, 2), &wsa);
if (err != 0)
{
//std::cout << "Failed. Error Code : " << err << std::endl;
QMessageBox Msgbox;
Msgbox.setText("Udp Connection Failed.");
Msgbox.exec();
exit(EXIT_FAILURE);
}
//Create a socket
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
// err = WSAGetLastError();
// std::cout << "Could not create socket : " << err << std::endl;
QMessageBox Msgbox;
Msgbox.setText("Could not create socket :");
Msgbox.exec();
exit(EXIT_FAILURE);
}
//Prepare the sockaddr_in structure
struct sockaddr_in server = {};
server.sin_family = AF_INET;
server.sin_port = htons(local_port);
if (local_addr)
{
server.sin_addr.s_addr = inet_addr(local_addr);
if (server.sin_addr.s_addr == INADDR_NONE)
{
// std::cout << "Invalid local address specified" << std::endl;
QMessageBox Msgbox;
Msgbox.setText("Invalid local address specified.");
Msgbox.exec();
closesocket(s);
exit(EXIT_FAILURE);
}
}
else
server.sin_addr.s_addr = INADDR_ANY;
//Bind
if (::bind(s, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
// err = WSAGetLastError();
// std::cout << "Bind failed with error code : " << err << std::endl;
QMessageBox Msgbox;
Msgbox.setText("Bind failed.");
Msgbox.exec();
closesocket(s);
exit(EXIT_FAILURE);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int UDPConnect::SendPacket(byte *buffer, unsigned int buf_size, const char* remote_addr, unsigned short remote_port)
{
struct sockaddr_in si_other = {};
int send_len;
//Prepare the sockaddr_in structure
si_other.sin_family = AF_INET;
si_other.sin_addr.s_addr = inet_addr(remote_addr);
si_other.sin_port = htons(remote_port);
if ((send_len = sendto(s, (char*)buffer, buf_size, 0, (struct sockaddr *) &si_other, sizeof(si_other))) == SOCKET_ERROR)
{
}
return send_len;
}
When I use the boost library to send data, I have no problem.
bool UDPConnect::send_udp_message(const std::string& message, const std::string& destination_ip, const unsigned short port)
{
boost::asio::io_service io_service;
boost::asio::ip::udp::socket socket(io_service);
// Create the remote endpoint using the destination ip address and
// the target port number. This is not a broadcast
auto remote = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string(destination_ip), port);
try {
// Open the socket, socket's destructor will
// automatically close it.
socket.open(boost::asio::ip::udp::v4());
// And send the string... (synchronous / blocking)
socket.send_to(boost::asio::buffer(message), remote);
}
catch (const boost::system::system_error& ex) {
// Exception thrown!
// Examine ex.code() and ex.what() to see what went wrong!
return false;
}
return true;
}
I code a small client for IPv4 / IPv6 with a hostname resolver.
For IPv4 and resolver it's fine but not with IPv6 when connect() I have a problem WSAGetLastError() say WSAEAFNOSUPPORT.
I have a switch all structures (AF_INET -> AF_INET6, SOCKADDR_IN -> SOCKADDR_IN6) to IPv6 versions.
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
printf("Simple_Client IPv4 & IPv6\n\n");
// Initiates Winsock
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 0), &WSAData);
// Get Parameters IP/PORT and request
std::string str_HOSTNAME = "mirror.neostrada.nl";
int PORT = 21;
// RESOLVE IP
BOOL is_IPv6 = FALSE;
std::string str_dest_ip = "";
addrinfo hints = { 0 };
hints.ai_flags = AI_ALL;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
addrinfo * pResult;
getaddrinfo(str_HOSTNAME.c_str(), NULL, &hints, &pResult);
if (pResult == NULL)
{
printf("pResult error\n");
return -1;
}
if (pResult->ai_family == AF_INET)
{
printf("getaddrinfo = AF_INET (IPv4)\n");
is_IPv6 = FALSE;
}
if (pResult->ai_family == AF_INET6)
{
printf("getaddrinfo = AF_INET6 (IPv6)\n");
is_IPv6 = TRUE;
}
char str[128];
memset(str, 0, sizeof(str));
if (is_IPv6 == FALSE) // IPv4
{
if (inet_ntop(AF_INET, &(*((ULONG*)&(((sockaddr_in*)pResult->ai_addr)->sin_addr))), str, INET_ADDRSTRLEN))
str_dest_ip = char_to_string(str, strlen(str)); // Copy char in std::string
else
printf("inet_ntop error\n");
}
if (is_IPv6 == TRUE) // IPv6
{
if (inet_ntop(AF_INET6, &(*((ULONG*)&(((sockaddr_in6 *)pResult->ai_addr)->sin6_addr))), str, INET6_ADDRSTRLEN))
str_dest_ip = char_to_string(str, strlen(str)); // Copy char in std::string
}
printf("%s : %s | Port : %i\n", is_IPv6 ? "IPv6" : "IPv4", str_dest_ip.c_str(), PORT);
// Connect to the HOSTNAME
SOCKET sock;
if (is_IPv6 == TRUE)
{
SOCKADDR_IN6 sin;
sin.sin6_family = AF_INET6;
if(inet_pton(sin.sin6_family, str_dest_ip.c_str(), &sin) != 1)
printf("ERROR inet_pton %i\n", WSAGetLastError());
sin.sin6_port = htons(PORT);
sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
return -2;
if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) != SOCKET_ERROR)
{
printf("Connect Success to %s | PORT : %i\n", str_dest_ip.c_str(), PORT);
}
else
{
printf("ERROR connect to %s | PORT : %i : %i\n", str_dest_ip.c_str(), PORT, WSAGetLastError());
Sleep(10000);
return -2;
}
}
char buf[1024] = { 0 };
int size_recv = recv(sock, buf, sizeof(buf), 0);
printf("SIZE RECV = %i | DATA RECV = %s\n", size_recv, char_to_string(buf, size_recv).c_str());
WSACleanup();
getchar();
return 0;
}
If somebody have a idea, thanks for reading.
The problem is here:
inet_pton(sin.sin6_family, str_dest_ip.c_str(), &sin)
This writes the IPv6 address on top of the sin6_family field, damaging the whole structure.
It should be:
inet_pton(sin.sin6_family, str_dest_ip.c_str(), &sin.sin6_addr)
It's also a good idea to zero-initialize the whole sin structure in the beginning because it has more fields than you're filling in.
You are not using getaddrinfo() correctly.
For one thing, getaddrinfo() returns an error code that you are ignoring.
For another thing, getaddrinfo() returns a linked list that potentially contains multiple addresses in a mix of IPv4 and/or IPv6, due to your use of AF_UNSPEC. If you are only interested in IPv6, set hints.ai_family to AF_INET6 rather than AF_UNSPEC.
But either way, a given hostname may have multiple IPs associated with it, and they might not all be reachable from your location, so you should be connect()'ing to each address in the list, either one at a time or in parallel, until one of them succeeds.
Also, there is no need to use inet_pton() in this situation at all (which you are not using correctly, as explained by #rustyx's answer). getaddrinfo() returns fully populated sockaddr_in(6) structs that you can pass as-is to connect().
Try something more like this instead:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>
#pragma comment(lib, "ws2_32.lib")
std::string addr_to_str(addrinfo *addr)
{
char str[128];
switch (addr->ai_family)
{
case AF_INET: // IPv4
{
if (inet_ntop(AF_INET, &(((sockaddr_in*)(addr->ai_addr))->sin_addr), str, INET_ADDRSTRLEN))
return str;
ret = WSAGetLastError();
break;
}
case AF_INET6: // IPv6
{
if (inet_ntop(AF_INET6, &(((sockaddr_in6*)(addr->ai_addr))->sin6_addr), str, INET6_ADDRSTRLEN))
return str;
ret = WSAGetLastError();
break;
}
default:
ret = WSAEAFNOSUPPORT;
break;
}
std::cerr << "inet_ntop error: " << ret << std::endl;
return "";
}
int main()
{
std::cout << "Simple_Client IPv4 & IPv6" << std::endl << std::endl;
// Initiates Winsock
WSADATA WSAData;
int ret = WSAStartup(MAKEWORD(2, 0), &WSAData);
if (ret != 0)
{
std::cerr << "WSAStartup error: " << ret << std::endl;
return -1;
}
// Get Parameters IP/PORT and request
std::string str_HOSTNAME = "mirror.neostrada.nl";
int PORT = 21;
// RESOLVE IP
addrinfo hints = { 0 };
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
addrinfo *pResult = NULL;
ret = getaddrinfo(str_HOSTNAME.c_str(), std::to_string(PORT).c_str(), &hints, &pResult);
if (ret != 0)
{
std::cerr << "getaddrinfo error: " << ret << std::endl;
WSACleanup();
return -1;
}
// Log the IPs
bool has_IPv4 = false;
bool has_IPv6 = false;
for (addrinfo *addr = pResult; addr != NULL; addr = addr->ai_next)
{
switch (addr->ai_family)
{
case AF_INET: // IPv4
{
has_IPv4 = true;
std::cout << "IPv4 : " << addr_to_str(addr);
break;
}
case AF_INET6: // IPv6
{
has_IPv6 = true;
std::cout << "IPv6 : " << addr_to_str(addr);
break;
}
}
}
// Connect to the HOSTNAME
SOCKET sock = INVALID_SOCKET;
if (has_IPv6)
{
// try IPv6 first...
for (addrinfo *addr = pResult; addr != NULL; addr = addr->ai_next)
{
if (addr->ai_family != AF_INET6)
continue;
std::cout << "Connecting to IPv6 : " << addr_to_str(addr) << " | Port : " << PORT << std::endl;
sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (sock == INVALID_SOCKET)
{
ret = WSAGetLastError();
std::cerr << "socket error: " << ret << std::endl;
continue;
}
if (connect(sock, addr->ai_addr, addr->ai_addrlen) == SOCKET_ERROR)
{
ret = WSAGetLastError();
std::cerr << "connect error: " << ret << std::endl;
closesocket(sock);
sock = INVALID_SOCKET;
continue;
}
break;
}
}
if ((sock == INVALID_SOCKET) && (has_IPv4))
{
// try IPv4 next...
for (addrinfo *addr = pResult; addr != NULL; addr = addr->ai_next)
{
if (addr->ai_family != AF_INET)
continue;
std::cout << "Connecting to IPv4 : " << addr_to_str(addr) << " | Port : " << PORT << std::endl;
sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (sock == INVALID_SOCKET)
{
ret = WSAGetLastError();
std::cerr << "socket error: " << ret << std::endl;
continue;
}
if (connect(sock, addr->ai_addr, addr->ai_addrlen) == SOCKET_ERROR)
{
ret = WSAGetLastError();
std::cerr << "connect error: " << ret << std::endl;
closesocket(sock);
sock = INVALID_SOCKET;
continue;
}
break;
}
}
freeaddrinfo(pResult);
if (sock == INVALID_SOCKET)
{
WSACleanup();
return -2;
}
std::cout << "Connect Successful" << std::endl;
char buf[1024];
int size_recv = recv(sock, buf, sizeof(buf), 0);
if (size_recv == SOCKET_ERROR)
{
ret = WSAGetLastError();
std::cerr << "recv error: " << ret << std::endl;
}
else
{
std::cout << "SIZE RECV = " << size_recv;
if (size_recv > 0)
{
std::cout << " | DATA RECV = ";
std::cout.write(buf, size_recv);
}
std::cout << std::endl;
}
closesocket(sock);
WSACleanup();
std::cin.get();
return 0;
}