Original Post
Firstly, my apologies for posting a boring "debug my code" topic, I've just been struggling with this for a few days and can't seem to identify the problem. Hopefully it's something quick and easy.
Anyway, I've written some basic TCP server and client code using the WinSock (and BSD sockets) API. Most of it is straight from Beej's TCP stream server tutorial. Unfortunately, I can't seem to get the client and server to connect on localhost. Here's what I've got:
WINSOCK/BSD COMPATIBILITY FIXES:
[source lang="cpp"]
#ifdef _WIN32
// The type for a socket handle.
typedef SOCKET SocketHandle;
// An invalid socket handle.
static const SocketHandle INVALID_SOCKET_HANDLE = INVALID_SOCKET;
#else
typedef SocketHandle int;
static const SocketHandle INVALID_SOCKET_HANDLE = -1;
#endif
// Returns the last error code.
int socketCheckError() {
#ifdef _WIN32
return WSAGetLastError();
#else
return errno;
#endif
}
#ifdef _WIN32
// Converts an error code the form for the appropriate platform.
#define socketErrorCode( code ) WSA ## code
#else
#define socketErrorCode( code ) code
#endif
[/source]
SERVER:
[source lang="cpp"]
// INITIALIZATION CODE:
LogThread::get().info() << "Attempting to initialize listening socket on port " << port;
// first get information about the server
addrinfo hints;
addrinfo * serverInfo;
SocketHandle socketId;
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
int result;
std::stringstream ss;
ss << port;
std::string portStr = ss.str();
result = getaddrinfo( NULL, portStr.c_str(), &hints, &serverInfo );
if (result) {
LogThread::get().error() << "Failed to initialize listening socket: could not get network info";
return false;
}
// try to bind to a socket
addrinfo * p;
for (p = serverInfo; p != NULL; p = p->ai_next) {
socketId = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
if (socketId == INVALID_SOCKET_HANDLE)
continue;
int intYes = 1;
if (setsockopt( socketId, SOL_SOCKET, SO_REUSEADDR, (char*)&intYes, sizeof( int ) )) {
LogThread::get().error() << "Failed to initialize listening socket: could not set socket options";
closesocket( socketId );
freeaddrinfo( serverInfo );
return false;
}
// set the socket to be nonblocking
#ifdef _WIN32
u_long ulongYes;
if (ioctlsocket( socketId, FIONBIO, &ulongYes )) {
#else
if (fcntl( socketId, F_SETFL, O_NONBLOCK )) {
#endif
LogThread::get().error() << "Failed to initialize listening socket: could not set socket to nonblocking mode";
closesocket( socketId );
freeaddrinfo( serverInfo );
return false;
}
if (bind( socketId, p->ai_addr, p->ai_addrlen )) {
closesocket( socketId );
continue;
}
break;
}
if (p == NULL) {
LogThread::get().error() << "Failed to initialize listening socket: could not find appropriate settings";
freeaddrinfo( serverInfo );
return false;
}
freeaddrinfo( serverInfo );
// listen on the socket
if (listen( socketId, SOMAXCONN )) {
LogThread::get().error() << "Failed to initialize listening socket: could not listen on socket";
closesocket( socketId );
return false;
}
listenSocketId = socketId;
LogThread::get().info() << "Initialized listening socket";
return true;
// NETWORK LISTENING CODE:
if (!init()) {
// ... blah, error stuff ...
} else {
while (!quit) {
// set up the read set for select and have it time out after 1 second (so we can quit rather than wait forever)
fd_set readSet;
FD_ZERO( &readSet );
FD_SET( listenSocketId, &readSet );
timeval timeout;
timeout.tv_usec = 0;
timeout.tv_sec = 1;
int selectResult = select( (int)(listenSocketId + 1), &readSet, NULL, NULL, &timeout );
// if selectResult is 0 we timed out, so loop again... otherwise:
if (selectResult < 0)
LogThread::get().error() << "select() failed";
else if (selectResult > 0) {
if (!FD_ISSET( listenSocketId, &readSet ))
LogThread::get().warning() << "select() returned without timing out but no network activity occurred";
else {
LogThread::get().info() << "Client connection attempt detected";
sockaddr_storage clientInfo;
int clientInfoSize = (int)sizeof( clientInfo );
SOCKET clientSocketId = accept( listenSocketId, (sockaddr*)&clientInfo, &clientInfoSize );
if (clientSocketId == INVALID_SOCKET_HANDLE)
LogThread::get().info() << "Failed to connect to client";
else {
char ip[INET_ADDRSTRLEN > INET6_ADDRSTRLEN ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN];
ip[0] = '?'; // in case getting the IP fails
ip[1] = '\0;';
if (clientInfo.ss_family == AF_INET)
inet_ntop( clientInfo.ss_family, &((sockaddr_in*)&clientInfo)->sin_addr, ip, sizeof( ip ) );
else if (clientInfo.ss_family == AF_INET6)
inet_ntop( clientInfo.ss_family, &((sockaddr_in6*)&clientInfo)->sin6_addr, ip, sizeof( ip ) );
LogThread::get().info() << "Connected to client " << ip << "; assigned ID: " << clientSocketId;
boost::mutex::scoped_lock lock( childThreadCountMutex );
++childThreadCount;
// create a thread to handle the client request
boost::thread connectionThread( (NetworkConnectionThread(
clientSocketId,
boost::function( boost::bind( &NetworkListenerThread::onChildThreadTerminate, this ) ) )) );
}
}
}
if (stopSignal)
quit = true;
}
closesocket( listenSocketId );
LogThread::get().info() << "Terminated listening socket";
}
[/source]
CLIENT (just up to connect):
[source lang="cpp"]
std::vector ret;
// get info about the server
addrinfo hints;
addrinfo * serverInfo;
SocketHandle socketId;
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
int result;
std::stringstream ss;
ss << port;
std::string portStr = ss.str();
result = getaddrinfo( ip.c_str(), portStr.c_str(), &hints, &serverInfo );
if (result)
return ret;
// try to connect
addrinfo * p;
for (p = serverInfo; p != NULL; p = p->ai_next) {
socketId = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
if (socketId == INVALID_SOCKET_HANDLE)
continue;
if (connect( socketId, p->ai_addr, p->ai_addrlen )) {
closesocket( socketId );
continue;
}
break;
}
// the connection now made if p != NULL
[/source]
(Also, I am calling WSAStartup() before this on Windows, so that isn't the problem.)
I'm attempting to run the server program on my computer and then connect using the client to 127.0.0.1. I'm using the same port on both and I've tried several with no luck. The sockets seem to be being initialized fine (functions are all returning 0 which is no error) but connect() always fails and select() never returns anything except for 0, i.e. timeout. I've also tried without using select() but instead just having it go straight to accept() but that also didn't work (accept simply never returned). Does anything look weird with the code I have? Thanks.
Anyway, I've written some basic TCP server and client code using the WinSock (and BSD sockets) API. Most of it is straight from Beej's TCP stream server tutorial. Unfortunately, I can't seem to get the client and server to connect on localhost. Here's what I've got:
WINSOCK/BSD COMPATIBILITY FIXES:
[source lang="cpp"]
#ifdef _WIN32
// The type for a socket handle.
typedef SOCKET SocketHandle;
// An invalid socket handle.
static const SocketHandle INVALID_SOCKET_HANDLE = INVALID_SOCKET;
#else
typedef SocketHandle int;
static const SocketHandle INVALID_SOCKET_HANDLE = -1;
#endif
// Returns the last error code.
int socketCheckError() {
#ifdef _WIN32
return WSAGetLastError();
#else
return errno;
#endif
}
#ifdef _WIN32
// Converts an error code the form for the appropriate platform.
#define socketErrorCode( code ) WSA ## code
#else
#define socketErrorCode( code ) code
#endif
[/source]
SERVER:
[source lang="cpp"]
// INITIALIZATION CODE:
LogThread::get().info() << "Attempting to initialize listening socket on port " << port;
// first get information about the server
addrinfo hints;
addrinfo * serverInfo;
SocketHandle socketId;
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
int result;
std::stringstream ss;
ss << port;
std::string portStr = ss.str();
result = getaddrinfo( NULL, portStr.c_str(), &hints, &serverInfo );
if (result) {
LogThread::get().error() << "Failed to initialize listening socket: could not get network info";
return false;
}
// try to bind to a socket
addrinfo * p;
for (p = serverInfo; p != NULL; p = p->ai_next) {
socketId = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
if (socketId == INVALID_SOCKET_HANDLE)
continue;
int intYes = 1;
if (setsockopt( socketId, SOL_SOCKET, SO_REUSEADDR, (char*)&intYes, sizeof( int ) )) {
LogThread::get().error() << "Failed to initialize listening socket: could not set socket options";
closesocket( socketId );
freeaddrinfo( serverInfo );
return false;
}
// set the socket to be nonblocking
#ifdef _WIN32
u_long ulongYes;
if (ioctlsocket( socketId, FIONBIO, &ulongYes )) {
#else
if (fcntl( socketId, F_SETFL, O_NONBLOCK )) {
#endif
LogThread::get().error() << "Failed to initialize listening socket: could not set socket to nonblocking mode";
closesocket( socketId );
freeaddrinfo( serverInfo );
return false;
}
if (bind( socketId, p->ai_addr, p->ai_addrlen )) {
closesocket( socketId );
continue;
}
break;
}
if (p == NULL) {
LogThread::get().error() << "Failed to initialize listening socket: could not find appropriate settings";
freeaddrinfo( serverInfo );
return false;
}
freeaddrinfo( serverInfo );
// listen on the socket
if (listen( socketId, SOMAXCONN )) {
LogThread::get().error() << "Failed to initialize listening socket: could not listen on socket";
closesocket( socketId );
return false;
}
listenSocketId = socketId;
LogThread::get().info() << "Initialized listening socket";
return true;
// NETWORK LISTENING CODE:
if (!init()) {
// ... blah, error stuff ...
} else {
while (!quit) {
// set up the read set for select and have it time out after 1 second (so we can quit rather than wait forever)
fd_set readSet;
FD_ZERO( &readSet );
FD_SET( listenSocketId, &readSet );
timeval timeout;
timeout.tv_usec = 0;
timeout.tv_sec = 1;
int selectResult = select( (int)(listenSocketId + 1), &readSet, NULL, NULL, &timeout );
// if selectResult is 0 we timed out, so loop again... otherwise:
if (selectResult < 0)
LogThread::get().error() << "select() failed";
else if (selectResult > 0) {
if (!FD_ISSET( listenSocketId, &readSet ))
LogThread::get().warning() << "select() returned without timing out but no network activity occurred";
else {
LogThread::get().info() << "Client connection attempt detected";
sockaddr_storage clientInfo;
int clientInfoSize = (int)sizeof( clientInfo );
SOCKET clientSocketId = accept( listenSocketId, (sockaddr*)&clientInfo, &clientInfoSize );
if (clientSocketId == INVALID_SOCKET_HANDLE)
LogThread::get().info() << "Failed to connect to client";
else {
char ip[INET_ADDRSTRLEN > INET6_ADDRSTRLEN ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN];
ip[0] = '?'; // in case getting the IP fails
ip[1] = '\0;';
if (clientInfo.ss_family == AF_INET)
inet_ntop( clientInfo.ss_family, &((sockaddr_in*)&clientInfo)->sin_addr, ip, sizeof( ip ) );
else if (clientInfo.ss_family == AF_INET6)
inet_ntop( clientInfo.ss_family, &((sockaddr_in6*)&clientInfo)->sin6_addr, ip, sizeof( ip ) );
LogThread::get().info() << "Connected to client " << ip << "; assigned ID: " << clientSocketId;
boost::mutex::scoped_lock lock( childThreadCountMutex );
++childThreadCount;
// create a thread to handle the client request
boost::thread connectionThread( (NetworkConnectionThread(
clientSocketId,
boost::function
}
}
}
if (stopSignal)
quit = true;
}
closesocket( listenSocketId );
LogThread::get().info() << "Terminated listening socket";
}
[/source]
CLIENT (just up to connect):
[source lang="cpp"]
std::vector
// get info about the server
addrinfo hints;
addrinfo * serverInfo;
SocketHandle socketId;
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
int result;
std::stringstream ss;
ss << port;
std::string portStr = ss.str();
result = getaddrinfo( ip.c_str(), portStr.c_str(), &hints, &serverInfo );
if (result)
return ret;
// try to connect
addrinfo * p;
for (p = serverInfo; p != NULL; p = p->ai_next) {
socketId = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
if (socketId == INVALID_SOCKET_HANDLE)
continue;
if (connect( socketId, p->ai_addr, p->ai_addrlen )) {
closesocket( socketId );
continue;
}
break;
}
// the connection now made if p != NULL
[/source]
(Also, I am calling WSAStartup() before this on Windows, so that isn't the problem.)
I'm attempting to run the server program on my computer and then connect using the client to 127.0.0.1. I'm using the same port on both and I've tried several with no luck. The sockets seem to be being initialized fine (functions are all returning 0 which is no error) but connect() always fails and select() never returns anything except for 0, i.e. timeout. I've also tried without using select() but instead just having it go straight to accept() but that also didn't work (accept simply never returned). Does anything look weird with the code I have? Thanks.