I get a Access violation reading location when i try to push a element in my vector in a function but if i do it in the class constructor it works.
header file of the class that gives problems
#include <winsock2.h>
#include <string>
#include <vector>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
class Network{
public:
/*
* General functions
*/
Network();
Network(bool debugModus);
~Network();
/*
* Server Functions
*/
int ServerSetup(int port);
void ServerAcceptConnections();
/*
* Server variable
*/
SOCKET m_client;
std::vector<SOCKET> m_clientList;
};
the cpp
void Network::ServerAcceptConnections()
{
SOCKET new_socket;
m_clientList.push_back(new_socket);
}
the main
void main ()
{
Network network (true);
network.ServerSetup(800);
while(true)
{
network.ServerAcceptConnections();
}
}
If i do the command:
m_clientList.push_back(new_socket);
In the class constructor it works and i can see it in the debugger,
but when I reach the ServerAcceptsConnection() function it doenst contain anny elements.
and if i try to add somthing there I get this error:
Unhandled exception at 0x00c730ab in server.exe: 0xC0000005: Access violation reading location 0x01000083.
edit the whole code
the header
#include <winsock2.h>
#include <string>
#include <vector>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
struct Message{
char* message;
unsigned int max_size;
unsigned int size;
};
class Network{
public:
/*
* General functions
*/
Network();
Network(bool debugModus);
int Connect(std::string ipAddress, int port);
int Send(SOCKET socket, char* message, unsigned int size);
Message Receive(SOCKET socket, int size = 2000);
~Network();
/*
* Server Functions
*/
int ServerSetup(int port);
void ServerAcceptConnections();
private:
/*
* General Functions
*/
int Init();
/*
* Server functions
*/
int Bind(int port);
int Listen();
/*
* General Variable
*/
bool m_debugModus;
WSADATA m_wsa;
SOCKET m_s;
struct sockaddr_in m_server;
/*
* Server variable
*/
SOCKET m_client;
std::vector<SOCKET> m_clientList;
std::vector<Message> m_outBuffer;
std::vector<Message> m_inBuffer;
};
the cpp
#include "NetworkClass.h"
#include<stdio.h>
Network::Network()
{
m_debugModus = false;
Init();
}
Network::Network(bool debugModus)
{
m_debugModus = true;
if(m_debugModus) printf("\nDEBUG MODUS!!");
if(m_debugModus) printf("\nThis mode is for debugging only!!");
if(m_debugModus) printf("\n");
if(m_debugModus) printf("\n");
Init();
}
int Network::Init()
{
SOCKET new_socket;
m_clientList.push_back(new_socket);
if(m_debugModus) printf("\nDEBUG MODUS: Initialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&m_wsa) != 0)
{
if(m_debugModus) printf("DEBUG MODUS: Failed. Error Code : %d",WSAGetLastError());
return 1;
}
if(m_debugModus) printf(" Initialised.\n");
/*
* creating a socket
*
* Settings:
* Address Family : AF_INET (this is IP version 4)
* Type : SOCK_STREAM (this means connection oriented TCP protocol)
* Protocol : 0 [ or IPPROTO_TCP , IPPROTO_UDP ]
*/
if((m_s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
if(m_debugModus) printf("DEBUG MODUS: Could not create socket : %d" , WSAGetLastError());
}
if(m_debugModus) printf("DEBUG MODUS: Socket created.\n");
return 0;
}
int Network::Connect(std::string ipAddress, int port)
{
if(m_debugModus) printf("DEBUG MODUS: Trying to connect with: %s on port %d \n", ipAddress.c_str(), port);
m_server.sin_addr.s_addr = inet_addr(ipAddress.c_str());
m_server.sin_family = AF_INET;
m_server.sin_port = htons( port );
if (connect(m_s , (struct sockaddr *)&m_server , sizeof(m_server)) < 0)
{
if(m_debugModus) printf("DEBUG MODUS: Error cant open a connecting\n", ipAddress, port);
return 1;
}
if(m_debugModus) printf("DEBUG MODUS: Connected\n");
return 0;
}
int Network::Send(SOCKET socket, char* message, unsigned int size)
{
if( send(socket , message , size , 0) < 0)
{
if(m_debugModus) printf("DEBUG MODUS: Send failed error: %d\n", WSAGetLastError());
return 1;
}
if(m_debugModus) printf("DEBUG MODUS: Data Send\n");
return 0;
}
Message Network::Receive(SOCKET socket, int size)
{
Message message;
message.message = (char*) malloc(sizeof(char)*size);
message.max_size = size;
if((message.size = recv(socket , message.message , message.max_size , 0)) == SOCKET_ERROR)
{
if(m_debugModus) printf("DEBUG MODUS: recv failed");
}
if(m_debugModus) printf("DEBUG MODUS: Reply received\n");
return message;
}
int Network::Bind(int port)
{
m_server.sin_family = AF_INET;
m_server.sin_addr.s_addr = INADDR_ANY;
m_server.sin_port = htons( port );
if( bind(m_s ,(struct sockaddr *)&m_server , sizeof(m_server)) == SOCKET_ERROR)
{
if(m_debugModus) printf("DEBUG MODUS: Bind failed with error code : %d\n" , WSAGetLastError());
return 1;
}
if(m_debugModus) printf("DEBUG MODUS: Bind done\n");
return 0;
}
int Network::Listen()
{
listen(m_s , 3);
return 0;
}
int Network::ServerSetup(int port)
{
Bind(port);
Listen();
return 0;
}
void Network::ServerAcceptConnections()
{
SOCKET new_socket;
int c = sizeof(struct sockaddr_in);
new_socket = accept(m_s , (struct sockaddr *)&m_client, &c);
if (new_socket != INVALID_SOCKET )
{
if(m_debugModus) printf("DEBUG MODUS: Connection accepted\n");
//Reply to the client
Send(new_socket, "Hello Client , I have received your connection. But I have to go now, bye\n", strlen("Hello Client , I have received your connection. But I have to go now, bye\n"));
m_clientList.push_back(new_socket);
}
if (new_socket == INVALID_SOCKET)
{
if(m_debugModus) printf("DEBUG MODUS: accept failed with error code : %d" , WSAGetLastError());
}
}
Network::~Network()
{
closesocket(m_s);
WSACleanup();
}
It looks like you are exceeding the capacity of the vector. In the while(true) loop, you are invoking network.ServerAcceptConnections(); function, which at each invocation constructs a SOCKET object, then pushes it into m_clientList, and it does this indefinitely (as the while runs indefinitely). At least this is what seems to happen looking at your code snipped.
On the other hand, the class constructor is invoked only once.
i found the problem
in the header the
SOCKET m_client;
goos out of bounderys
if i put the vector above this line it works
Related
I'm just starting to learn the C++ and I would like to test what I'm learning on a Raspberry. My project, for now, consist to transfert data from a Raspberry to another through WiFi. This works very well but the problem comes when the Raspberry client disconnects from WiFi. At this time, the Server wait indefinitely. So to avoid that, I search on Google to have a Timeout function and here it is:
class Timeout;
static Timeout * global_timeout_instance = 0;
class Timeout {
public:
int m_timeout;
jmp_buf env;
Timeout(int timeout) : m_timeout(timeout) {
if (global_timeout_instance) {
throw "Timeout already in use";
}
global_timeout_instance = this;
}
~Timeout() {
stop();
global_timeout_instance = 0;
}
static void alarm_handler(int signum) {
longjmp(global_timeout_instance->env, 1);
}
void start() {
Timeout * ptr = this;
if (setjmp(env) != 0) {
// Don't do anything except throw here, since the state
// is... funky...
printf("Alarm fired: %p\n", ptr);
throw global_timeout_instance;
}
signal(SIGALRM, alarm_handler);
alarm(2);
}
void stop() {
alarm(0);
}
};
So this function works very well because when the connection is lost, the program stop directly. But I would like to do some action after the loss of connection. So here is my entire code:
#include <exception>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <cstdio>
#include <setjmp.h>
#include <signal.h>
class Timeout;
static Timeout * global_timeout_instance = 0;
class Timeout {
public:
int m_timeout;
jmp_buf env;
Timeout(int timeout) : m_timeout(timeout) {
if (global_timeout_instance) {
throw "Timeout already in use";
}
global_timeout_instance = this;
}
~Timeout() {
stop();
global_timeout_instance = 0;
}
static void alarm_handler(int signum) {
longjmp(global_timeout_instance->env, 1);
}
void start() {
Timeout * ptr = this;
if (setjmp(env) != 0) {
// Don't do anything except throw here, since the state
// is... funky...
printf("Alarm fired: %p\n", ptr);
throw global_timeout_instance;
}
signal(SIGALRM, alarm_handler);
alarm(2);
}
void stop() {
alarm(0);
}
};
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , read_size;
struct sockaddr_in server , client;
char client_message[2000];
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
//accept connection from an incoming client
client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
puts("Connection accepted");
//Receive a message from client
while(1)
{
try
{
Timeout timeout(1);
timeout.start();
read_size = recv(client_sock , client_message , 2000 , MSG_WAITALL);
}
catch(Timeout * t)
{
printf("Timeout detected\n");
// Do some action later
}
printf("%d\n", read_size);
if(client_message !="")
{
puts(client_message);
}
else
{
printf("Not Ok");
}
memset(client_message, 0, sizeof(client_message));
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
return 0;
}
I don't know how I can do some action after the Timeout.
Here is the message I received when the program stop:
Alarm fired: 0x7eff8c40 terminate called after throwing an instance of
'Timeout*' Aborted
Can someone help me on this problem?
Thank you.
Kevin
In a project I am currently doing in group, we have to build a card game from scratch that uses sockets (Linux). We also have to build a chat room that every player can use.
So far so good. The chat is implemented using three separate threads, one that receives incoming connections (up to 50) and stores them in a client list, one that constantly waits for messages from all connected clients, and one that is created each time a client sends a message, sending that message to all clients in the client list. All of this works, except when a single client disconnects.
I managed to keep the server alive (with a sig handler for SIGPIPE) when a client disconnects, but now, when a client disconnects, I keep getting the error Bad file descriptor. But that's not the only problem, since the server keeps receiving empty messages and sends them to the remaining clients, effectively flooding the whole chat in a matter of milliseconds with empty messages.
I believe that if I can fix the problem on the server side, there won't be any problems on the client side.
So my question is: What is the right way (or any way) to manage a Bad file descriptor in my case. I've already tried closing the socket FD and setting the value to -1 in the client list, but that created even more problems and didn't fix the initial ones.
Here is the code, if necessary. The most important function (for the chat) are reception_thread, chat_thread, receive_string, send_string and connect_to_chat on the client side.
Here is the client:
//includes
const int PORT = 2477;
const int CHAT_PORT = 2478;
#define DEBUG
//error()
// Sets up the connection to the server.
//connect_to_server()
int connect_to_chat(char * hostname)
{
#ifdef DEBUG
printf("[DEBUG] Initiating connection to chat server.\n");
#endif
struct sockaddr_in serv_addr;
struct hostent *server;
// Get a socket.
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("Error opening socket for server.");
// Get the address of the server.
server = gethostbyname(hostname);
if (server == NULL) {
fprintf(stderr, "ERROR, no such host\n");
exit(0);
}
// Zero out memory for server info.
memset(&serv_addr, 0, sizeof (serv_addr));
// Set up the server info.
serv_addr.sin_family = AF_INET;
memmove(server->h_addr, &serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(CHAT_PORT);
// Make the connection.
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error("Error connecting to chat server");
#ifdef DEBUG
printf("[DEBUG] Connected to server.\n");
#endif
return sockfd;
}
//-------------------------------- Messages ------------------------------------
// Bunch of send/recv functions that are not important to chat
int send_string(int sockfd, std::string myString)
{
#ifdef DEBUG
printf("[DEBUG] Sending string: %s.\n", myString.c_str());
#endif
//send size
uint32_t stringLen = myString.size();
uint32_t sendLen = htonl(stringLen);
int n = send(sockfd, &sendLen, sizeof (uint32_t), 0);
if (n < 0) {
error("Error sending message (string size). Removing client from list.");
return -1;
}
//send string
n = send(sockfd, myString.c_str(), stringLen, 0);
if (n < 0) {
error("Error sending message (string). Removing client from list.");
return -1;
}
return 0;
}
std::string receive_string(int sockfd)
{
//get string length
uint32_t stringLen;
int n = recv(sockfd, &stringLen, sizeof (uint32_t), 0);
if (n < 0) {
perror("Error receiving message(string size).");
}
stringLen = ntohl(stringLen);
std::vector<uint8_t> buffer;
buffer.resize(stringLen, 0x00);
//get string
n = recv(sockfd, &(buffer[0]), stringLen, 0);
if (n < 0) {
perror("Error receiving message(string).");
}
std::string returnString;
returnString.assign(reinterpret_cast<const char*> (&(buffer[0])), buffer.size()); //might be a bad idea, but it works
#ifdef DEBUG
printf("[DEBUG] Received message: %s\n", returnString.c_str());
#endif
return returnString;
}
//----------------------------- Printing functions------------------------------
void print_menu_guest()
{
// some visual function
}
void print_menu_user()
{
// some visual function
}
void print_info()
{
std::cout << " No information available on the game yet." << std::endl;
}
//---------------------------- Account functions -------------------------------
// Not necessary for chat functions
//--------------------------- Chat thread functions ----------------------------
void reception_thread(int sockfd)
{
#ifdef DEBUG
printf("[DEBUG] Reception thread started.\n");
#endif
std::string stringToPrint;
while (1) {
stringToPrint = receive_string(sockfd);
std::cout << stringToPrint << std::endl;
}
}
void chat_thread(int sockfd, char* host)
{
#ifdef DEBUG
printf("[DEBUG] Chat thread started.\n");
#endif
std::string myString, myUsername, blank;
std::cout << "Enter your username (NO SPACES): ";
std::cin >> myUsername;
myUsername += ": ";
int chat_sockfd = connect_to_chat(host);
std::thread reception_thr(reception_thread, chat_sockfd);
reception_thr.detach();
while (1) {
getline(std::cin, myString);
if (!myString.empty()) {
if (myString != "/quit") {
send_string(chat_sockfd, (myUsername + myString));
}
else {
printf("On peut pas encore quitter :( ");
}
}
}
}
//---------------------- Menu management functions -----------------------------
// Main menu function
//---------------------------- Main function -----------------------------------
int main(int argc, char** argv)
{
/* Make sure host and port are specified. */
if (true) {
char* hostname = "localhost";
/* Connect to the server. */
int sockfd = connect_to_server(hostname);
#ifdef DEBUG
printf("[DEBUG] Client ID: Not yet implemented. ");
#endif
login_prompt(sockfd);
user_menu_loop(sockfd);
}
return 0;
}
And here is the server: Its most important functions (for the chat) are setup_user_fetcher, message_receiver, send_string_to_all, receive_string, send_string, get_chat_user, setup_chat_listener.
// Bunch of includes
const int PORT = 2477;
const int CHAT_PORT = 2478;
const int BACKLOG = 10;
const int MAX_CLIENTS = 20;
int clients_list[50] = {-1};
#define DEBUG
void error(const char *msg)
{
perror(msg);
}
/* Catch Signal Handler functio */
void signal_callback_handler(int signum){
printf("Caught signal SIGPIPE %d\n",signum);
}
//-------------------------- Server set-up functions ---------------------------
// Not necessary for chat
//--------------------------- Chat server functions ---------------------------
int setup_chat_listener()
{
int sockfd;
struct sockaddr_in serv_addr;
// Get a socket to listen on
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening listener socket.");
// Zero out the memory for the server information
memset(&serv_addr, 0, sizeof (serv_addr));
// set up the server info
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(CHAT_PORT);
// Bind the server info to the listener socket.
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error("Error binding listener socket.");
#ifdef DEBUG
printf("[DEBUG] Chat listener set.\n");
#endif
// Return the socket number.
return sockfd;
}
int get_chat_user(int sockfd)
{
#ifdef DEBUG
printf("[DEBUG] Getting chat user.\n");
#endif
struct sockaddr_in their_addr;
socklen_t sin_size;
if (listen(sockfd, BACKLOG) < 0) {
perror("Error while listening.");
exit(EXIT_FAILURE);
}
sin_size = sizeof (struct sockaddr_in);
// Mise a zero de la memoire pour le client.
memset(&their_addr, 0, sin_size);
int new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size);
if (new_fd < 0)
error("Error while accepting.");
printf("Chat server: Connection received from: %s\n",
inet_ntoa(their_addr.sin_addr));
return new_fd;
}
int send_string(int sockfd, std::string myString)
{
#ifdef DEBUG
printf("[DEBUG] Sending string to client %d.\n", sockfd);
#endif
uint32_t stringLen = myString.size();
uint32_t sendLen = htonl(stringLen);
int n = send(sockfd, &sendLen, sizeof (uint32_t), 0);
if (n < 0) {
error("Error sending message (string size). Removing client from list.");
return -1;
}
//send string
n = send(sockfd, myString.c_str(), stringLen, 0);
if (n < 0) {
error("Error sending message (string). Removing client from list.");
return -1;
}
return 0;
}
std::string receive_string(int sockfd)
{
#ifdef DEBUG
printf("[DEBUG] Receiving string.\n");
printf("Current chat user sockfd: %d\n", sockfd);
#endif
uint32_t stringLen;
int n = recv(sockfd, &stringLen, sizeof (uint32_t), 0);
#ifdef DEBUG
printf("[DEBUG] String size received: %d.\n", stringLen);
#endif
if (n < 0) {
perror("Error receiving message(string size).");
}
stringLen = ntohl(stringLen);
std::vector<uint8_t> buffer;
buffer.resize(stringLen, 0x00);
//get string
n = recv(sockfd, &(buffer[0]), stringLen, 0);
if (n < 0) {
perror("Error receiving message(string).");
close(sockfd);
}
std::string returnString;
returnString.assign(reinterpret_cast<const char*> (&(buffer[0])), buffer.size()); //might be a bad idea, but it works
#ifdef DEBUG
printf("[DEBUG] Received message: %s\n", returnString.c_str());
#endif
return returnString;
}
void send_string_to_all(std::string myString)
{
#ifdef DEBUG
printf("[DEBUG] Sending string to all clients.\n");
#endif
int n;
for (int i = 0; i < 50; ++i) {
if (clients_list[i] != -1) {
n = send_string(clients_list[i], myString);
if (n < 0) {
close(clients_list[i]);
clients_list[i] = -1;
}
}
}
}
void message_receiver(int sockfd)
{
#ifdef DEBUG
printf("[DEBUG] Setting up message receiver.\n");
printf("Current chat user sockfd: %d", sockfd);
#endif
std::string message;
int n;
while (1) {
message = receive_string(sockfd);
std::thread t1(send_string_to_all, message);
t1.detach();
}
}
//------------------------------------------------------------------------------
// Bunch of send/recv functions, not necessary to chat
//----------------------------Account Functions---------------------------------
// Not necessary to chat
//------------------------------------------------------------------------------
// Main menu function
void setup_user_fetcher(int lis_chat_sockfd)
{
#ifdef DEBUG
printf("[DEBUG] Gotta catch'em all.\n");
#endif
while (1) {
int chat_user_sockfd = get_chat_user(lis_chat_sockfd);
for (int i = 0; i < 50; ++i)
if (clients_list[i] == -1) {
clients_list[i] = chat_user_sockfd;
break;
}
std::thread message_receiver_thread(message_receiver, chat_user_sockfd);
message_receiver_thread.detach();
}
}
int main(int argc, char** argv)
{
signal(SIGPIPE, signal_callback_handler);
int lis_sockfd = setup_listener();
int lis_chat_sockfd = setup_chat_listener();
std::thread chat_thread(setup_user_fetcher, lis_chat_sockfd);
chat_thread.detach();
while (1) {
int user_sockfd = get_user(lis_sockfd);
int* user_sockfd_ptr = (int*) malloc(sizeof (int));
memset(user_sockfd_ptr, 0, sizeof (int));
user_sockfd_ptr[0] = user_sockfd;
#ifdef DEBUG
printf("[DEBUG] Starting main menu...\n");
#endif
pthread_t thread;
int result = pthread_create(&thread, NULL, main_menu,
(void *) user_sockfd_ptr);
if (result) {
printf("Thread creation failed with return code %d\n", result);
exit(-1);
}
#ifdef DEBUG
printf("[DEBUG] New main menu thread started.\n");
#endif
}
close(lis_sockfd);
pthread_exit(NULL);
return 0;
}
If you wish to reproduce the error, you could compile the code using the following lines
g++ client.cpp -o client -std=c++14 -pthread
g++ server.cpp -o server -std=c++14 -pthread
and run both without any arguments. The client is set to connect on "localhost".
I would be really glad if anyone could help me out with this.
I recomment getting rid of the SIGPIPE signal itself.
signal(SIGPIPE, SIG_IGN);
Now, write()s on killed sockets will simply return -1. It should be easier to deal with that, instead of an asynchronous signal.
If you need SIGPIPE for other reasons, replace write()s with sendto()s with the MSG_NOSIGNAL option. See the sendto(2) manual page for more information.
You have UB. &(buffer[0]) will fail if the number of bytes read is 0 (which I believe will happen if client disconnects). You should test for 0 and return early before building your string.
Also you do not return after finding errors so you build your string from bad data in case of errors.
Maybe something more like:
std::string receive_string(int sockfd)
{
uint32_t stringLen;
int n = recv(sockfd, &stringLen, sizeof (uint32_t), 0);
if (n < 0) {
close(sockfd);
// exit early
throw std::runtime_error("Error receiving message(string size): "
+ std::string(std::strerror(errno)));
}
// test for zero
if(!n)
return {}; // empty string
stringLen = ntohl(stringLen);
std::vector<uint8_t> buffer(stringLen);
// buffer.resize(stringLen, 0x00);
//get string
n = recv(sockfd, &(buffer[0]), stringLen, 0);
if (n < 0) {
close(sockfd);
// exit early
throw std::runtime_error("Error receiving message(string): "
+ std::string(std::strerror(errno)));
}
// only build string if no errors
return {buffer.begin(), buffer.begin() + n};
}
So I have a winsock application in which the computer tries to accept a client, and then starts a new thread with the a pointer to the class object with client info which it copies and then deletes with the delete keyword.
The backbone is copied but the beginning of the OOP-structure is my work and the current implementation seems to be giving me some issues.
I noticed the socket might not copy in the correct format, but have no idea on how to fix this. As the client tries to connect it throws me the error message of that the server refused the connection. Anyway, here is the code of the server.
UPDATE:
It's working.
// main.h
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <process.h>
#include <cstring>
#include <iostream>
#include <stdio.h>
#include <memory>
#pragma comment(lib,"ws2_32.lib" )
class clientData{
private:
SOCKET clientSocket;
std::string name;
public:
clientData(SOCKET &clientSock, const char *tName);
clientData(clientData *cliDat);
~clientData();
inline SOCKET *getClientSocket(){
return &clientSocket;
}
inline std::string *getName(){
return &name;
}
};
And here is the main cpp file
// main.cpp
#include "main.h"
unsigned int __stdcall ServClient(void *data);
int main(int argc, char *argv[])
{
WSADATA wsaData;
int iResult;
sockaddr_in addr;
SOCKET sock, client[10];
addr.sin_family = AF_INET;
addr.sin_port = htons(13337);
addr.sin_addr.S_un.S_addr = INADDR_ANY;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);//2.2
if (iResult)
{
printf("WSA startup failed");
return 0;
}
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
{
printf("Invalid socket");
return 0;
}
int addrlen = sizeof(sockaddr_in);
iResult = bind(sock, (sockaddr*)&addr, sizeof(sockaddr_in));
if (iResult)
{
printf("bind failed %u", GetLastError());
return 0;
}
iResult = listen(sock, SOMAXCONN);
if (iResult)
{
printf("iResult failed %u", GetLastError());
return 0;
}
int iterationCount = 0;
while ((iterationCount < 10 &&
(client[iterationCount] = accept(sock, (SOCKADDR*)&addr, &addrlen)) != SOCKET_ERROR))
{
if (client[iterationCount] == INVALID_SOCKET){
printf("invalid client socket",GetLastError());
continue;
}
++iterationCount;
char tempName[100] = { '\0' };
sprintf_s(tempName, sizeof(tempName), "Client %u", iterationCount);
clientData *tempCLdata = new clientData(client[iterationCount - 1], tempName);
_beginthreadex(0, 0, ServClient, (void*)tempCLdata, 0, 0);
tempCLdata = nullptr;
}
return 0;
}
unsigned int __stdcall ServClient(void *data)
{
clientData cliDat((clientData*)data);
delete (clientData*)data;
printf("Client connected\n");
int recvLen = 1;
char chunk[1024] = { '\0' };
while ((recvLen = recv(*cliDat.getClientSocket(), chunk, 1024, 0)) > 0){
printf("%.*s", recvLen, chunk);
}
if (recvLen == -1)
perror("Socket recv() problem..\n");
else
printf("End of data on socket, closing..\n");
closesocket(*cliDat.getClientSocket());
return 0;
}
clientData::clientData(SOCKET &clientSock, const char *tName){
clientSocket = clientSock;
name.assign(tName);
}
clientData::clientData(clientData *cliDat){
SOCKET *clientSocketPtr = cliDat->getClientSocket();
clientSocket = *clientSocketPtr;
name.assign(cliDat->getName()->c_str());
}
clientData::~clientData(){
}
Also here is the relevant bit of client code, as requested.
char buffer[1023] = { '\0' };
int heartbeatCount = 0;
while (true)
{
sprintf_s(buffer, sizeof(buffer), "Heartbeat %d", heartbeatCount + 1);
send(sock, buffer, strlen(buffer) + 1, 0);
++heartbeatCount;
Sleep(1000);
}
I've wrote a simple client code in python, and I'm trying to connect to a simple echo server written in C.
I know it shouldn't matter, but for some reason I did manage to connect to a server written in python, but I cannot connect to the C server.
Here's the code of the client:
import socket
import sys
import time
HOST = 'localhost'
PORT = 11000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
msg = raw_input()
s.send(msg)
data = s.recv(len(msg))
s.close()
print 'Received: ', data
And here's the C code of the echo server:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#ifndef AF_INET
#define AF_INET 2
#endif
#ifndef SOCK_DGRAM
#define SOCK_DGRAM 2
#endif
#ifndef INADDR_ANY
#define INADDR_ANY 0
#endif
#ifndef IP_DONTFRAG
#define IP_DONTFRAG 67
#endif
#define BUFFER_SIZE 1024
#define ECHO_PORT_UDP 10000
#define ECHO_PORT_TCP 11000
int main(int argc, char *argv[]) {
int echo_socket = 0;
int echo_socket_child = 0; // for TCP
struct sockaddr_in server;
struct sockaddr_in client;
struct hostent *hostp; // client host info
struct sockaddr_in clientaddr; // client addr
char *hostaddrp; // dotted decimal host addr string
char buffer[BUFFER_SIZE];
unsigned int clientlen = 0;
unsigned int serverlen = 0;
int received = 0;
int port = 0;
char *endptr;
int optval = 1;
int msg_byte_size = 0;
// Parameters check
if (argc == 2) {
port = strtol(argv[1], &endptr, 0);
if ((*endptr) || ((port != ECHO_PORT_UDP) && (port != ECHO_PORT_TCP))) {
printf("EchoServer: Invalid port number.\n Use port %d for UDP, port %d for TCP.\n", ECHO_PORT_UDP, ECHO_PORT_TCP);
return -1;
}
else {
if (port == ECHO_PORT_UDP) {
printf("EchoServer: Running UDP on port %d.\n", port);
}
if (port == ECHO_PORT_TCP) {
printf("EchoServer: Running TCP on port %d.\n", port);
}
}
}
else {
printf("EchoServer: Invalid arguments.\n");
return -1;
}
// Opening UDP socket
if (port == ECHO_PORT_UDP) {
if ((echo_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
printf("EchoServer: Failed opening socket");
return -1;
}
}
if (port == ECHO_PORT_TCP) {
if ((echo_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("EchoServer: Failed opening socket");
return -1;
}
// setsockopt: Handy debugging trick that lets us rerun the server immediately after we kill it; otherwise we have to wait about 20 secs.
// Eliminates "ERROR on binding: Address already in use" error.
setsockopt(echo_socket, SOL_SOCKET, SO_REUSEADDR,(const void *)&optval , sizeof(int));
}
// Construct the server sockaddr_in structure
memset(&server, 0, sizeof(server)); /* Clear struct */
server.sin_family = AF_INET; /* Internet/IP */
server.sin_addr.s_addr = htonl(INADDR_ANY); /* Any IP address */
server.sin_port = htons(atol(argv[1])); /* server port */
// Bind the socket
serverlen = sizeof(server);
if (bind(echo_socket, (struct sockaddr *) &server, serverlen) < 0) {
printf("EchoServer: Failed binding socket");
return -1;
}
// Wait for a datagram until cancelled
if (port == ECHO_PORT_UDP) {
while (1) {
/* Receive a message from the client */
clientlen = sizeof(client);
if ((received = recvfrom(echo_socket, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client, &clientlen)) < 0) {
printf("EchoServer: Failed receiving datagram");
return -1;
}
printf("Client datagram received from: %s\n", inet_ntoa(client.sin_addr));
/* Send the message back to client */
if (sendto(echo_socket, buffer, received, 0, (struct sockaddr *) &client, sizeof(client)) != received) {
printf("Mismatch in number of echoed bytes");
return -1;
}
}
}
// Wait for a connection until cancelled
if (port == ECHO_PORT_TCP) {
while (1) {
echo_socket_child = accept(echo_socket, (struct sockaddr *) &client, &clientlen);
if (echo_socket_child < 0) {
printf("ERROR on accept");
break;
}
// gethostbyaddr: determine who sent the message
hostp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr, sizeof(clientaddr.sin_addr.s_addr), AF_INET);
if (hostp == NULL) {
printf("ERROR on gethostbyaddr");
break;
}
hostaddrp = inet_ntoa(clientaddr.sin_addr);
if (hostaddrp == NULL) {
printf("ERROR on inet_ntoa\n");
break;
}
printf("server established connection with %s \n", hostaddrp);
// read: read input string from the client
bzero(buffer, BUFFER_SIZE);
msg_byte_size = read(echo_socket_child, buffer, BUFFER_SIZE);
if (msg_byte_size < 0) {
printf("ERROR reading from socket");
break;
}
printf("server received %d bytes: %s", msg_byte_size, buffer);
// write: echo the input string back to the client
msg_byte_size = write(echo_socket_child, buffer, strlen(buffer));
if (msg_byte_size < 0) {
printf("ERROR writing to socket");
break;
}
} // endof while(1)
close(echo_socket_child);
return -1;
}
return 0;
}
Any ideas why I fail to connect to the server?
edit:
this is the error I receive:
Traceback (most recent call last):
File "s.py", line 8, in <module>
s.connect((HOST, PORT))
File "C:\Python27\lib\socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 10061]
(1) Add a listen call to the TCP section of the code.
(2) You have to tell accept what the length of the sockaddr you are passing it is and it will in return tell you the length of the address of the client it returned. You were passing it as 0 length so naturally it didn't pass back a client address which subsequently makes your gethostbyaddr fail with unknown address.
(3) If you don't close the client socket within the loop it just remains open (and leaks a file descriptor) for the duration of the server's life. Eventually you will run out of FDs. It doesn't effect your client which just closes after the receipt of one msg but any client who writes more than one message will never have it received by the server and will never receive an eof from the server.
if (port == ECHO_PORT_TCP)
{
if (listen(echo_socket, ECHO_PORT_TCP) == -1)
{
perror("listen");
exit(1);
}
while (1)
{
clientlen = sizeof(client);
echo_socket_child = accept(echo_socket, (struct sockaddr *) &client, &clientlen);
if (echo_socket_child < 0)
{
perror("accept");
break;
}
// gethostbyaddr: determine who sent the message
hostp = gethostbyaddr((const char *) &client.sin_addr.s_addr, sizeof(client.sin_addr.s_addr), AF_INET);
if (hostp == NULL)
{ herror("byaddr");
break;
}
hostaddrp = inet_ntoa(client.sin_addr);
if (hostaddrp == NULL)
{
printf("ERROR on inet_ntoa\n");
break;
}
printf("server established connection with %s (%s)\n", hostp->h_name, hostaddrp);
bzero(buffer, BUFFER_SIZE);
msg_byte_size = read(echo_socket_child, buffer, BUFFER_SIZE);
if (msg_byte_size < 0)
{
printf("ERROR reading from socket");
break;
}
printf("server received %d bytes: %s", msg_byte_size, buffer);
msg_byte_size = write(echo_socket_child, buffer, strlen(buffer));
if (msg_byte_size < 0)
{
printf("ERROR writing to socket");
break;
}
close(echo_socket_child);
} // endof while(1)
return -1;
}
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
}