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
Related
I am developing an C++ service to achieve IPC using Unix domain socket in Linux.
How can I perform Unit Testing to test CreateSocket and RunServer class method all use case?
Can someone suggest a way to perform Unit Testing for such kind of IPC communication service ? I am new to Unit Testing.
I am not sure how to design class such a way that I can perform Unit Testing.
Need to Test following Functionality for Unit Testing:
CreateSocket - success
CreateSocket - Failed at unlink system call
CreateSocket - Failed at socket system call
CreateSocket - Failed at bind system call
CreateSocket - Failed at listen system call
RunServer - Success
RunServer - Failed at accept system call
RunServer - Failed at read system call
RunServer - Failed at write system call
RunServer - Failed at default switch case error case
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/stat.h>
#define SERVER_SOCKET "/dev/ipcserver"
#define TOTAL_QUEUE_CONNECTION 10
enum message_type
{
REQUEST,
RESPONSE,
DICONNECT
};
struct message
{
message_type type;
char data [50];
};
class Server
{
private:
int server_socket_fd;
fd_set fds, readfds;
int fdmax;
struct message message;
public:
int CreateSocket(void);
int RunServer();
Server()
{
FD_ZERO (&fds);
FD_ZERO (&readfds);
}
~Server()
{
}
};
int Server::CreateSocket()
{
// create a unix domain socket,
struct stat statbuf;
if (stat (SERVER_SOCKET, &statbuf) == 0)
{
if (unlink (SERVER_SOCKET) == -1)
{
printf ("unlink failed \n");
return -1;
}
}
if ((server_socket_fd = socket (AF_UNIX, SOCK_SEQPACKET, 0)) == -1)
{
printf ("socket failed \n ");
return -1;
}
struct sockaddr_un socket_address;
memset (&socket_address, 0, sizeof (struct sockaddr_un));
socket_address.sun_family = AF_UNIX;
strncpy (socket_address.sun_path, SERVER_SOCKET, sizeof(socket_address.sun_path) - 1);
if (bind (server_socket_fd, (const struct sockaddr *) &socket_address, sizeof (struct sockaddr_un)) == -1)
{
printf ("bind failed \n");
return -1;
}
if (listen (server_socket_fd, TOTAL_QUEUE_CONNECTION) == -1)
{
printf ("listen failed \n");
return -1;
}
FD_SET (server_socket_fd, &fds);
fdmax = server_socket_fd;
return 0;
}
int Server::RunServer()
{
while (1)
{
readfds = fds;
// monitor readfds for readiness for reading
if (select (fdmax + 1, &readfds, NULL, NULL, NULL) == -1)
{
printf ("select failed \n");
return -1;
}
// Some sockets are ready. Examine readfds
for (int fd = 0; fd < (fdmax + 1); fd++)
{
if (FD_ISSET (fd, &readfds))
{ // fd is ready for reading
if (fd == server_socket_fd)
{ // request for new connection
int fd_new;
if ((fd_new = accept (server_socket_fd, NULL, NULL)) == -1)
{
printf ("accept failed \n");
}
FD_SET (fd_new, &fds);
if (fd_new > fdmax)
{
fdmax = fd_new;
}
}
else // data from an existing connection
{
memset (&message, '\0', sizeof (struct message));
ssize_t numbytes = read (fd, &message, sizeof (struct message));
if (numbytes == -1)
{
printf ("read failed \n");
}
else
{
printf ("Data received from client : \n");
switch (message.type)
{
case REQUEST:
{
memset (&message, '\0', sizeof (struct message));
char data[] = {0x01,0x02,0x03,0x04,0x05,0x06};
memcpy(message.data,data,sizeof(data));
message.type = RESPONSE;
if (write (fd, &message, sizeof (struct message)) == -1)
{
printf ("write error \n");
}
break;
}
case DICONNECT: // clear client connection from monitored fd set
{
FD_CLR(fd,&fds);
}
default:
{
printf ("Unexpected message from client\n");
break;
}
}
}
}
} // if
} // for
} // while (1)
return 0;
}
int main()
{
Server IPCServer;
int status = IPCServer.CreateSocket();
if(status == 0)
{
IPCServer.RunServer();
}
else
{
printf("IPCServer create fail\n");
return -1;
}
return 0;
}
I have two pairs of simple TCP server/client, i.e., one client per server, running on Windows:
Servers run in a process (app).
Clients run in the other process.
Servers keep sending heartbeats (a string) to their paired client.
The first pair of server/client run their mainloops in their own threads.
Once the first server/client have shaken hands with the first heartbeat, the second pair of server/client start their mainloops in their own threads.
For this test, they run on the same machine with different ports: 2345 and 2346.
Now my problem
The first client receives its server's heartbeat.
The second client does NOT, although the second server sent out heartbeats without errors.
Here is the server code:
// hello_dualchannel_server.cpp : This file contains the 'main' function.
#include "pch.h"
#include <iostream>
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <spdlog/spdlog.h>
#define SPDLOG_WCHAR_TO_UTF8_SUPPORT
#ifdef _DEBUG
#if !defined(SPDLOG_ACTIVE_LEVEL)
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
#endif // #if !defined(SPDLOG_ACTIVE_LEVEL)
#define SPDLOG_DEBUG_ON
#define SPDLOG_TRACE_ON
#define _trace SPDLOG_TRACE
#endif // #ifdef _DEBUG
using namespace spdlog;
SOCKET g_sockFirst = 0;
SOCKET g_sockClientFirst = 0;
std::thread g_threadFirst;
uint32_t g_timeLatestHeartBeatFirst = 0;
SOCKET g_sockSecond = 0;
SOCKET g_sockClientSecond = 0;
std::thread g_threadSecond;
uint32_t g_timeLatestHeartBeatSecond = 0;
void SetupLogger() {
#ifdef _DEBUG
spdlog::set_level(spdlog::level::trace);
spdlog::set_pattern("[%H:%M:%S%z][%^%L%$][%t:%s:%#] %v");
#else
spdlog::set_level(spdlog::level::info);
spdlog::set_pattern("[%H:%M:%S][%^%L%$][%t] %v");
#endif // #ifdef _DEBUG
}
int InitWinSock() {
WORD wVersionRequested;
WSADATA wsaData;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
return 1;
}
/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we */
/* requested. */
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return 1;
}
else
printf("The Winsock 2.2 dll was found okay\n");
return 0;
}
bool Init(int host_port, SOCKET* p_sockServer, SOCKET*p_sockClient) {
int err = 0;
int* p_int = 0;
std::string host_name("127.0.0.1");
struct sockaddr_in my_addr;
int addr_size = 0;
sockaddr_in sadr_client;
if (!*p_sockServer) {
*p_sockServer = socket(AF_INET, SOCK_STREAM, 0);
if (*p_sockServer == -1) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Server Error initializing socket: {}", log);
goto FINISH;
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if ((setsockopt(*p_sockServer, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1)
|| (setsockopt(*p_sockServer, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1)) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Server Error setting options: {}", log);
free(p_int);
goto FINISH;
}
free(p_int);
info("Server socket is set up.");
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(*p_sockServer, (sockaddr*)&my_addr, sizeof(my_addr)) == -1) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Server Error binding to socket, make sure nothing else is listening on this port: {}", log);
goto FINISH;
}
if (listen(*p_sockServer, 10) == -1) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Server Error listening: {}", log);
goto FINISH;
}
info("SUCCESS: Server socket listening ...");
}
info("Server accepting connection ...");
addr_size = sizeof(sockaddr_in);
char sAddress[MAX_PATH];
*p_sockClient = accept(*p_sockServer, (sockaddr*)&sadr_client, &addr_size);
if (*p_sockClient == INVALID_SOCKET) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Server error accepting client connection: {}", log);
// DO NOT close sockets here.
return false;
}
inet_ntop(sadr_client.sin_family, &sadr_client.sin_addr, sAddress, MAX_PATH);
g_timeLatestHeartBeatFirst = GetCurrentTime();
info("SUCCESS: Server accepted client connection.");
return true;
FINISH:
closesocket(*p_sockServer);
return false;
}
bool IsConnected(uint32_t timeLatestHeartBeat) {
// CAUTION: denser than client for sure catch
const unsigned long ConnTimeoutMs = 300;
auto cur = GetCurrentTime();
auto latest = timeLatestHeartBeat;
return cur - latest < ConnTimeoutMs;
}
bool StayInTouch(const char* name, SOCKET* pSockClient, uint32_t* pTimeLatestHeartBeat) {
if (IsConnected(*pTimeLatestHeartBeat))
return true;
char heartBeat[] = "biku";
int nBytesSent = 0;
int flags = 0;
int res = send(*pSockClient, heartBeat, sizeof(heartBeat), flags);
if (res == SOCKET_ERROR) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("{}: Server failed to send heartbeat: {}, Windows error: {}", name, log, GetLastError());
return false;
}
else if (res == 0) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("{}: Server sent zerobyte heartbeat: {}", name, log);
return false;
}
debug("{}: Heartbeat sent: {}", name, heartBeat);
*pTimeLatestHeartBeat = GetCurrentTime();
return true;
}
void Close(SOCKET* pSock) {
closesocket(*pSock);
*pSock = 0;
}
bool Connect() {
if (g_threadFirst.joinable()) {
warn("FirstTunnel already running. Skipped.");
return true;
}
g_threadFirst = std::thread([&]() {
bool isConnected = false;
while (true) {
while (!isConnected) {
isConnected = Init(2345, &g_sockFirst, &g_sockClientFirst);
}
isConnected = StayInTouch("FirstTunnel", &g_sockClientFirst, &g_timeLatestHeartBeatFirst);
if (!isConnected) {
// We don't close as client.
// We keep connecting
error("About to reconnect ...");
Sleep(1000);
continue;
}
if (!g_threadSecond.joinable()) {
g_threadSecond = std::thread([&]() {
while (true) {
while (!isConnected) {
isConnected = Init(2346, &g_sockSecond, &g_sockClientSecond);
}
isConnected = StayInTouch("SecondTunnel", &g_sockClientSecond, &g_timeLatestHeartBeatSecond);
if (!isConnected) {
// We don't close as client.
// We keep connecting
error("About to reconnect ...");
Sleep(1000);
continue;
}
}
info("SecondTunnel quitting...");
Close(&g_sockSecond);
});
}
}
info("FirstTunnel quitting...");
Close(&g_sockFirst);
});
while (true) {
//info("main thread ...");
Sleep(3000);
}
return g_threadFirst.joinable() ? true : false;
}
int main() {
SetupLogger();
info("Hello World!\n");
if (InitWinSock()) {
critical("Failed to initialize Window socket. Aborted.");
}
Connect();
if (g_threadSecond.joinable()) {
g_threadSecond.join();
}
if (g_threadFirst.joinable()) {
g_threadFirst.join();
}
WSACleanup();
info("Bye!");
}
Here is the client code
// hello_dualchannel_client.cpp : This file contains the 'main' function.
//
#include "pch.h"
#include <iostream>
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <spdlog/spdlog.h>
#define SPDLOG_WCHAR_TO_UTF8_SUPPORT
#ifdef _DEBUG
#if !defined(SPDLOG_ACTIVE_LEVEL)
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
#endif // #if !defined(SPDLOG_ACTIVE_LEVEL)
#define SPDLOG_DEBUG_ON
#define SPDLOG_TRACE_ON
#define _trace SPDLOG_TRACE
#endif // #ifdef _DEBUG
using namespace spdlog;
SOCKET g_sockFirst = 0;
std::thread g_threadFirst;
uint32_t g_timeLatestHeartBeatFirst;
SOCKET g_sockSecond = 0;
std::thread g_threadSecond;
uint32_t g_timeLatestHeartBeatSecond;
void SetupLogger() {
#ifdef _DEBUG
spdlog::set_level(spdlog::level::trace);
spdlog::set_pattern("[%H:%M:%S%z][%^%L%$][%t:%s:%#] %v");
#else
spdlog::set_level(spdlog::level::info);
spdlog::set_pattern("[%H:%M:%S][%^%L%$][%t] %v");
#endif // #ifdef _DEBUG
}
int InitWinSock() {
WORD wVersionRequested;
WSADATA wsaData;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
return 1;
}
/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we */
/* requested. */
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return 1;
}
else
printf("The Winsock 2.2 dll was found okay\n");
return 0;
}
bool Init(int host_port, SOCKET* p_sock) {
int err = 0;
int* p_int = 0;
std::string host_name("127.0.0.1");
struct sockaddr_in my_addr;
char handshake[] = "hello";
//int nBytesSent;
if (!*p_sock) {
*p_sock = socket(AF_INET, SOCK_STREAM, 0);
if (*p_sock == -1) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Client Error initializing socket {}", log);
goto FINISH;
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if ((setsockopt(*p_sock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1)
|| (setsockopt(*p_sock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1)) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Client Error setting options {}", log);
free(p_int);
goto FINISH;
}
free(p_int);
info("SUCCESS: Client socket is set up.");
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
inet_pton(my_addr.sin_family, host_name.c_str(), &my_addr.sin_addr);
if (connect(*p_sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == SOCKET_ERROR) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Client Error connecting socket {}", log);
Sleep(1000);
goto FINISH;
}
/*nBytesSent = send(g_sockFirst, handshake, sizeof(handshake), 0);
if (nBytesSent <= 0) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Client error sending handshake: {}", log);
goto FINISH;
}*/
g_timeLatestHeartBeatFirst = GetCurrentTime();
info("SUCCESS: Client connected to server.");
return true;
FINISH:
closesocket(*p_sock);
*p_sock = 0;
return false;
}
bool IsConnected(uint32_t timeLatestHeartBeat) {
const unsigned long ConnTimeoutMs = 3000;
auto cur = GetCurrentTime();
auto latest = timeLatestHeartBeat;
//if (cur - latest > ConnTimeoutMs)
//{
// debug("cur: {}, late: {}", cur, latest);
//}
return cur - latest < ConnTimeoutMs;
}
bool StayInTouch(const char* name, SOCKET* pSock, uint32_t* pTimeLatestHeartBeat) {
// Client checks inbox right away and measure timeout later.
char heartBeat[MAX_PATH] = { 0 };
// CAUTION: min 100ms required for receiving heartbeat.
//const uint32_t TimeoutMS = 100;
int flags = 0;
int nBytesRecved = recv(*pSock, heartBeat, sizeof(heartBeat), flags);
bool gotHeartbeat = nBytesRecved > 0;
if (gotHeartbeat) {
debug("{}: Heartbeat received: {}", name, heartBeat);
*pTimeLatestHeartBeat = GetCurrentTime();
}
return IsConnected(*pTimeLatestHeartBeat);
}
void Close(SOCKET* pSock) {
closesocket(*pSock);
*pSock = 0;
}
bool Connect() {
if (g_threadFirst.joinable()) {
warn("FirstTunnel already running. Skipped.");
return true;
}
g_threadFirst = std::thread([&]() {
bool isConnected = false;
while (true) {
while (!isConnected) {
isConnected = Init(2345, &g_sockFirst);
}
isConnected = StayInTouch("FirstTunnel", &g_sockFirst, &g_timeLatestHeartBeatFirst);
if (!isConnected) {
// We don't close as client.
// We keep connecting
Close(&g_sockFirst);
error("About to reconnect ...");
continue;
}
if (!g_threadSecond.joinable()) {
g_threadSecond = std::thread([&]() {
while (true) {
while (!isConnected) {
isConnected = Init(2346, &g_sockSecond);
}
isConnected = StayInTouch("SecondTunnel", &g_sockSecond, &g_timeLatestHeartBeatSecond);
if (!isConnected) {
// We don't close as client.
// We keep connecting
error("About to reconnect ...");
Sleep(1000);
continue;
}
}
info("SecondTunnel quitting...");
Close(&g_sockSecond);
});
}
}
info("FirstTunnel quitting.");
Close(&g_sockFirst);
});
while (true) {
//info("main thread ...");
Sleep(3000);
}
return g_threadFirst.joinable() ? true : false;
}
int main() {
SetupLogger();
info("Hello World!\n");
if (InitWinSock()) {
critical("Failed to initialize Window socket. Aborted.");
}
Connect();
if (g_threadSecond.joinable()) {
g_threadSecond.join();
}
if (g_threadFirst.joinable()) {
g_threadFirst.join();
}
WSACleanup();
info("Bye!");
}
The main connection logic is in the function Connect().
I'd appreciate tips on where I was wrong.
To run the code as is, you need one dependency spdlog
vcpkg install spdlog:x64-Windows
You can also replace all the spdlog-based logging code with your own.
UPDATE
Observation #1
I stepped into the code and confirmed
All the loops are running. So all the threads are spawned.
No redundant threads are spawned due to the joinable() guard.
The only failure point is the recv call of the second client.
So conclusion
No firewalls
No redundant threads
Both threads run on the client and server sides by design.
Observation #2
While running the server and client programs and having let the problem happen, I tried
Keep both programs open.
Run netcat (NMap's netcat port) like this C:\Apps\Nmap\ncat.exe 127.0.0.1 2346
This actually help fix things. It tells me that there is a connection problem, while I could definitely step into the client code and see that the connection is still there.
Observation #3
After I leave breakpoints in only the second connection code of the client program, and run the program, I could not step out into the first connection code. Note that they are in separate threads.
Leaving breakpoints in both connections, and quickly step over between them, I could keep the stepping going without getting trapped in only one thread. This is when I notice that the client starts receiving the messages it should.
So I suspect that there is a threading issue there. If that's the problem, How to fix this then?
I found the problem myself. It was a stupid bug on my part:
The two threads share a state by mistake: isConnected. So the original programs keep kicking each other after one of them gains a new connection or heartbeat. They should have used different states for that.
To give more detail: isConnected, which is initialized by g_threadFirst, falls through the closure of g_threadSecond's anonymous function.
I created a BSD-POSIX TCP Socket class and now i have a problem.I have two wifi networks.One of them is an ADSL Router , and another one is hotspoted by an Android device.When i connect to ADSL Router wifi , i can't receive any data at all.The socket can send data , but there is no response.But when i connect to hotspoted wifi (Android device) , the program can receive data.I don't know what is the problem.Both WIFI Networks working fine.And also i used Wireshark to capture data.Data sent successful , but there is no receive.Here is my code:
-------------------ESocket.cpp---------------------
#include "ESocket.h"
#include "stdio.h"
SOCKET s = NULL;
ESocket::ESocket(string ip,int port)
{
struct sockaddr_in server;
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == -1)
{
s = NULL;
}
server.sin_addr.s_addr = inet_addr(ip.c_str());
server.sin_family = AF_INET;
server.sin_port = htons( port );
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
s = NULL;
}
}
ESocket::ESocket(SOCKET e)
{
s = e;
}
ESocket::~ESocket()
{
Destruct();
}
bool ESocket::isConnected()
{
return (s != NULL);
}
int ESocket::Destruct()
{
#ifdef _WIN32
return WSACleanup();
#else
return 0;
#endif
}
int ESocket::Close()
{
int status = 0;
#ifdef _WIN32
status = shutdown(s, SD_BOTH);
if (status == 0) { status = closesocket(s); }
#else
status = shutdown(s, SHUT_RDWR);
if (status == 0) { status = close(s); }
#endif
return status;
}
bool ESocket::SendData(string data)
{
if( send(s , data.c_str() , data.length() , 0) < 0)
{
s = NULL;
return false;
}
return true;
}
string ESocket::ReceiveData(int len)
{
int recv_size;
char reply[len];
if((recv_size = recv(s , reply , len , 0)) < 0)
{
return "";
}
if (recv_size == 0)
{
s = NULL;
return "";
}
printf("%i",recv_size);
reply[recv_size] = '\0';
return reply;
}
int ESocket::setAsNonBlock()
{
int res;
#ifdef _WIN32
u_long iMode = 1;
res = ioctlsocket(s, FIONBIO, &iMode);
#else
int opts;
opts = fcntl(s, F_GETFL);
if(opts < 0)
{
res = -1;
}
opts = (opts | O_NONBLOCK);
if(fcntl(s, F_SETFL, opts) < 0)
{
res = -1;
}
#endif
return res;
}
-------------------ESocket.h---------------------
#ifndef ESOCKET_H
#define ESOCKET_H
#include <string>
#include <stdio.h>
#include <cstring>
using namespace std;
#ifdef _WIN32
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include <winsock2.h>
#else
typedef int SOCKET;
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#endif
class ESocket
{
public:
ESocket(string ip,int port);
ESocket(SOCKET e);
virtual ~ESocket();
int Destruct();
int Close();
int setAsNonBlock();
bool SendData(string data);
bool isConnected();
string ReceiveData(int len);
static int Init()
{
#ifdef _WIN32
WSADATA wsa_data;
return WSAStartup(MAKEWORD(1,1), &wsa_data);
#else
return 0;
#endif
}
static string getIP(char* host)
{
struct hostent *he;
struct in_addr **addr_list;
char ip[100];
int i;
if ( (he = gethostbyname( host ) ) == NULL)
{
return "";
}
addr_list = (struct in_addr **) he->h_addr_list;
for(i = 0; addr_list[i] != NULL; i++)
{
strcpy(ip , inet_ntoa(*addr_list[i]) );
}
string x = ip;
return x;
}
protected:
private:
};
#endif // ESOCKET_H
------------------------MAIN-----------------------
ESocket::Init();
ESocket e(ESocket::getIP("www.google.com").c_str(),80);
if (e.isConnected())
{
cout<<e.SendData("GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: keep-alive\r\n\r\n");
}
else
{
printf("Not connected");
return 0;
}
while (e.isConnected()){
cout<<e.ReceiveData(100);
}
printf("\nEND OF CONNECTION");
EDIT: Solved by reset wifi router.
You have several serious bugs:
Your receive function has no code to support the "would block" condition and so it will not work reliably with non-blocking sockets.
Your receive function provides no reliable way to tell whether it got an error or not (as opposed to an empty string). It corrupts the socket value on an error, so calling it again after an error is potentially disastrous. Yet it provides no way at all to avoid this.
You set the socket to NULL. But nothing makes NULL an invalid value for a socket. On WIN32, use INVALID_SOCKET. On other platforms, use -1.
You also have a more minor issue. Your request claims HTTP 1.1 compliance, but it is not an HTTP 1.1 compliant request. For example, HTTP 1.1 makes "Host" headers mandatory. Don't claim compliance with a protocol you have no intention of supporting. What happens if you get back a reply that uses chunked encoding?
Likely what's happening is that receive is encountering a "would block" condition, corrupting the socket, and then you call receive again with an invalid socket which, of course, fails.
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
I can't seem to get working 2 watchers per socket.. Code below doesn't acually works at all, but if i mix up these calls(for ex. call init/set/start for 1 watcher and then for other), i get only 1 watcher working.. Is there something I'm missing badly here...?
I don't think it has anything to do with loops and setup... I have 1 accept loop(default loop) and 1 loop for accepted connections. I tried both, running code below directly after accepting connection on accept loop and via ev_async_send(...) then executing this code from other io loop. Results were same.
Also setting both events on 1 watcher works fine too.
Thank you
ev_init (pSockWatcher->_wW, &CNetServer::send_cb);
ev_init (pSockWatcher->_wR, &CNetServer::recv_cb);
ev_io_set (pSockWatcher->_wW, pSockWatcher->_sd, EV_WRITE );
ev_io_set (pSockWatcher->_wR, pSockWatcher->_sd, EV_READ );
ev_io_start (loop, pSockWatcher->_wR);
ev_io_start (loop, pSockWatcher->_wW);
Well, here is an example with two I/O watchers on one socket fd, which seems to work fine for me. I am using the ev_io_init() function, however, not the ev_init() and ev_set().
#include <ev.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
static struct ev_loop *loop;
static ev_timer timeout_watcher;
static ev_io in_watcher, out_watcher;
static ev_idle idle_watcher;
static int sock_fd;
// socket input watcher
static void in_cb(EV_P_ ev_io *watcher, int revents) {
int r, t;
char buf[1024];
for (t = 0; (r = read(sock_fd, buf, sizeof(buf))) > 0;) {
t += r;
write(STDOUT_FILENO, buf, r); // copy input to stdout
if (buf[r-1] == '\n') break; // operate line-at-a-time
}
fprintf(stderr, "in: count = %d\n", t);
if (r == 0) {
fputs("in: connection closed\n", stderr);
ev_io_stop(loop, &in_watcher); // stop the socket watcher
ev_break(loop, EVBREAK_ALL); // exit the loop
} else if (r < 0) {
perror("read");
}
}
// socket output watcher
static void out_cb(EV_P_ ev_io *watcher, int revents) {
int r, t, lim;
char buf[1024];
ev_io_stop(loop, &out_watcher);
for (t = 0; t < sizeof(buf); t++) {
buf[t] = 'a' + (rand() % 26);
}
for (t = 0, lim = rand() % 10000 + 1000;
(r = write(sock_fd, buf, (lim - t > sizeof(buf)) ? sizeof(buf) : lim - t)) > 0;) {
t += r;
if (t >= lim) break;
}
if (r < 0) {
perror("write");
}
fprintf(stderr, "out: finished sending, count = %d\n", t);
}
static void timeout_cb(EV_P_ ev_timer *watcher, int revents) {
fprintf(stderr, "timeout: now = %f\n", ev_now(loop));
// send a bunch of stuff on the socket when able
ev_io_start (loop, &out_watcher);
}
static void idle_cb(EV_P_ ev_idle *watcher, int revents) {
static long idle_count = 0;
fprintf(stderr, "idle: count = %ld\n", ++idle_count);
sleep(1); // simulate doing stuff
}
int main() {
extern int errno;
int master_fd;
int sock_opt = 1;
int conn_port = 7000;
struct sockaddr_in addr;
socklen_t addrlen;
// **** the following is needed to set up a socket to receive data ****
master_fd = socket(AF_INET, SOCK_STREAM, 0);
if (master_fd == -1) {
perror("socket");
return errno;
}
if (setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &sock_opt, sizeof(sock_opt)) == -1) {
perror("setsockopt");
return errno;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(conn_port);
addrlen = sizeof(addr);
if (bind(master_fd, (struct sockaddr *) &addr, addrlen) != 0) {
perror("bind");
return errno;
}
if (listen(master_fd, 3) != 0) {
perror("listen");
return errno;
}
fprintf(stderr, "awaiting a connection on port %d\n", conn_port);
sock_fd = accept(master_fd, (struct sockaddr *) &addr, &addrlen);
if (sock_fd == -1) {
perror("accept");
return errno;
}
fputs("in: connection established\n", stderr);
// **** end of socket setup code ****
// define a loop
loop = ev_default_loop(0);
// define a repeating timer
ev_timer_init (&timeout_watcher, timeout_cb, 5.0, 5.0);
ev_timer_start (loop, &timeout_watcher);
// define an idle process
ev_idle_init(&idle_watcher, idle_cb);
ev_idle_start (loop, &idle_watcher);
// define the socket data receiver
ev_io_init(&in_watcher, in_cb, sock_fd, EV_READ);
ev_io_start (loop, &in_watcher);
// define the socket data write complete watcher
ev_io_init(&out_watcher, out_cb, sock_fd, EV_WRITE);
// run the loop
ev_run(loop, 0);
// clean up
close(sock_fd);
close(master_fd);
return 0;
}