I am creating a listener socket to listen for client connections on a particular port. When accept()
is invoked, my understanding is that it should return a newly created socket on a unique port (so the listener can continue accepting clients on the connection/listener port).
However, the behavior I am seeing is that the newly created socket returned by accept()
is bound to the same port that the listener socket is on. My below example accepts only one client, but I see the same behavior even if accepting multiple clients – every “handler” socket gets created on the same port.
I doubt this is a bug in the Winsock library, but I’m running out of ideas. My best guess is that I have a misunderstanding about how to properly deal with accepting clients onto new sockets.
Notes:
- I’m not seeing any errors from the library function calls
- The sockets returned by
accept()
all have unique socket IDs (so they appear to be valid new sockets)
Here is a simple program that should demonstrate the issue (at least it does for me). It should build as-is, only linking to ws2_32. Simply run 2 instances of the executable – one server and one client. Then enter the server connection info in the client instance to connect and see the issue.
#include <winsock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <string>
#pragma comment(lib, "Ws2_32.lib")
int RunServer();
int RunClient();
int main()
{
// Initialize Winsock (Windows socket library)
std::cout << "Initializing Winsock..." << std::endl;
WSACleanup();
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cout << "Failed to initialize Winsock" << std::endl;
return 1;
}
// Run instance as either the server or the client (ask the user)
char choice;
std::cout << std::endl << "Do you want to run as a server (s) or client (c)?: ";
std::cin >> choice;
std::cout << std::endl;
if (choice == 's')
{
RunServer();
}
else
{
RunClient();
}
// Cleanup
WSACleanup();
}
int RunServer()
{
// Create listener socket
std::cout << "Creating listener socket..." << std::endl;
SOCKET listenerSocket = INVALID_SOCKET;
listenerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listenerSocket == INVALID_SOCKET)
{
std::cerr << "Error creating socket: " << WSAGetLastError() << std::endl;
return 1;
}
// Bind the socket
std::cout << "Binding the listener socket..." << std::endl << std::endl;
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = 0x0189A8C0; // 192.168.137.1
service.sin_port = htons(12345);
int iResult = bind(listenerSocket, (SOCKADDR*)&service, sizeof(service));
if (iResult == SOCKET_ERROR)
{
std::cerr << "bind failed: " << WSAGetLastError() << std::endl;
return 1;
}
// Get & print listener socket info
sockaddr_in listenerSocketAddress{};
int listenerSocketAddressLength = sizeof(listenerSocketAddress);
getsockname(listenerSocket, reinterpret_cast<struct sockaddr*>(&listenerSocketAddress), &listenerSocketAddressLength);
std::cout << "Listener IP Address: " << inet_ntoa(listenerSocketAddress.sin_addr) << std::endl;
std::cout << "** Listener Port: " << ntohs(listenerSocketAddress.sin_port) << " **" << std::endl << std::endl;
// Listen
std::cout << "Listening for clients..." << std::endl;
iResult = listen(listenerSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR)
{
std::cerr << "listen failed: " << WSAGetLastError() << std::endl;
return 1;
}
// Accept
std::cout << "Waiting to accept client..." << std::endl << std::endl;
sockaddr_in clientSocketAddress{};
int clientSocketAddressLength = sizeof(clientSocketAddress);
SOCKET clientHandlerSocket = INVALID_SOCKET;
clientHandlerSocket = accept(listenerSocket, reinterpret_cast<struct sockaddr*>(&clientSocketAddress), &clientSocketAddressLength);
if (clientHandlerSocket == INVALID_SOCKET)
{
std::cerr << "accept failed: " << WSAGetLastError() << std::endl;
return 1;
}
std::cout << "Accepted a client!" << std::endl;
std::cout << "Client's IP Address: " << inet_ntoa(clientSocketAddress.sin_addr) << std::endl;
std::cout << "Client's Port: " << ntohs(clientSocketAddress.sin_port) << std::endl << std::endl;
// Get & print the weird client handler socket info shenanigans
sockaddr_in clientHandlerSocketAddress{};
int clientHandlerSocketAddressLength = sizeof(clientHandlerSocketAddress);
if (getsockname(clientHandlerSocket, reinterpret_cast<struct sockaddr*>(&clientHandlerSocketAddress), &clientHandlerSocketAddressLength) == SOCKET_ERROR)
{
std::cerr << "getsockname failed: " << WSAGetLastError() << std::endl;
return 1;
}
std::cout << "Connected to Client via IP Address: " << inet_ntoa(clientHandlerSocketAddress.sin_addr) << std::endl;
std::cout << "** Connected to Client via Port: " << ntohs(clientHandlerSocketAddress.sin_port) << " **" << std::endl << "^^^ This should have been created on a different port than the listener socket, right??" << std::endl << std::endl;
// Double check that the new socket (returned by 'accept') is actually connected to the expected client
//sockaddr_in clientSocketAddress2{};
//int clientSocketAddress2Length = sizeof(clientSocketAddress2);
//if (getpeername(clientHandlerSocket, reinterpret_cast<struct sockaddr*>(&clientSocketAddress2), &clientSocketAddress2Length) == SOCKET_ERROR)
//{
// std::cerr << "getpeername failed: " << WSAGetLastError() << std::endl;
// return 1;
//}
//std::cout << "Double checking the connected client... (this should match the info that 'accept' returned)" << std::endl;
//std::cout << "Client's IP Address: " << inet_ntoa(clientSocketAddress2.sin_addr) << std::endl;
//std::cout << "Client's Port: " << ntohs(clientSocketAddress2.sin_port) << std::endl << std::endl;
system("PAUSE");
return 0;
}
int RunClient()
{
// Create client socket
std::cout << "Creating client socket..." << std::endl;
SOCKET clientSocket = INVALID_SOCKET;
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET)
{
std::cerr << "Error creating socket: " << WSAGetLastError() << std::endl;
return 1;
}
// Request server socket info from the user
std::string serverIP;
int serverPort;
std::cin.ignore();
std::cout << std::endl << "Enter the server's IP address: ";
std::getline(std::cin, serverIP);
std::cout << "Enter the server's port number: ";
std::cin >> serverPort;
std::cin.ignore();
if (serverIP.empty())
{
// If IP is omitted, I guess try localhost?
serverIP = "127.0.0.1";
}
// Connect to the server
sockaddr_in serverAddr{};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(serverPort);
struct in_addr address {};
if (inet_pton(AF_INET, serverIP.c_str(), &address) != 1)
{
// Error handling: Invalid IP address format
return 1;
}
serverAddr.sin_addr.s_addr = address.s_addr;
int status = connect(clientSocket, reinterpret_cast<struct sockaddr*>(&serverAddr), sizeof(serverAddr));
if (status != 0)
{
std::cerr << "connect failed: " << WSAGetLastError() << std::endl;
return 1;
}
std::cout << std::endl << "Connected to server!" << std::endl << std::endl;
// Double check that the new socket (returned by 'accept') is actually connected to the expected client
sockaddr_in serverSocketAddress{};
int serverSocketAddressLength = sizeof(serverSocketAddress);
if (getpeername(clientSocket, reinterpret_cast<struct sockaddr*>(&serverSocketAddress), &serverSocketAddressLength) == SOCKET_ERROR)
{
std::cerr << "getpeername failed: " << WSAGetLastError() << std::endl;
return 1;
}
std::cout << "Server's comm socket IP Address: " << inet_ntoa(serverSocketAddress.sin_addr) << std::endl;
std::cout << "** Server's comm socket Port: " << ntohs(serverSocketAddress.sin_port) << " **" << std::endl;
std::cout << "^^^ The server should be communicating on a different port than the connection port, right??" << std::endl << std::endl;
system("PAUSE");
return 0;
}