I'm currently trying to implement a class to create and use TCP connections.
(I'm quite new in c++ so it's possible that I forgot something obvious, even though I've been seriously checking my code)
Note that later I'll be implementing a second class to handle new connections so there are some parts of the code that are incomplete/arranged and I hope that this won't disturb you while trying to understand it.
Here's my problem:
The server and the client both seem to work fine (I'm always checking on my listen, bind, connect functions: no error) and I'm apparently able to send data with the client but when I try to read it from the server, I get WSA error 10038 (which means that I'm executing the recv() on an invalid socket). I've been looking it up for a few days now and can't seem to find my mistake. Besides the tests in the code, I've used "netstat -an -p tcp" to check the state of the connection and everything appears fine but the server just won't receive the data.
NB: I'm using Visual Studio 6 (Yup, it's old, but it's mandatory so...) and winsock, not winsock2.
If I forgot something just ask, I'm trying to be as complete as possible but it's not impossible to forget something.
Here are my source codes, I tried to cut it to the essential but I'm afraid that the mistake can be pretty much anywhere:
CmTcpTransport.cpp
/**
Initializes the TCP connection (socket) in CLIENT or SERVER mode.
It does not connect yet.
@param strIPAddress: IP Address to reach
nPort: Port to connect to
hSocket: client Socket if SERVER mode
nTcpMode: mode for this connexion SERVER(1) or CLIENT(2)
@return an int to get the exit point of the function
*/
int CmTcpTransport::initialize(std::string strIPAddress, unsigned int nPort, SOCKET hSocket, int nTcpMode)
{
m_nTcpMode = nTcpMode;
cout << "Creating TCP connexion..." << endl << endl;
if (nTcpMode == 1) // SERVER
{
serveraddr.sin_family = AF_INET; // address family Internet
serveraddr.sin_port = htons (nPort); // Port to connect on
serveraddr.sin_addr.s_addr = inet_addr (strIPAddress.c_str()); // Target IP
cout << "SERVER: Retrieving socket information..." << endl;
if (hSocket == INVALID_SOCKET)
{
return 102; // The received socket is invalid
cout << "SERVER: Socket creation failed" << endl;
}
serverSocket = hSocket;
cout << "SERVER: Listening socket received" << endl;
if (bind(serverSocket, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == SOCKET_ERROR)
{
return 103; // Couldn't bind
cout << "SERVER: Socket binding failed" << endl;
}
else {
cout << "SERVER: Binding successful" << endl;
}
if (listen(serverSocket, 1) == SOCKET_ERROR)
{
return 103; // Couldn't listen
cout << "SERVER: Socket listening failed" << endl;
}
else {
cout << "SERVER: Listening to socket" << endl;
}
}
else // CLIENT
{
serveraddr.sin_family = AF_INET; // address family Internet
serveraddr.sin_port = htons (nPort); // Port to connect on
serveraddr.sin_addr.s_addr = inet_addr (strIPAddress.c_str()); // Target IP
cout << "CLIENT: Creating client socket..." << endl;
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // CREATE CLIENT SOCKET
if (clientSocket == INVALID_SOCKET)
{
return 104; // Couldn't create the socket
cout << "CLIENT: Socket creation failed" << endl;
}
cout << "CLIENT: Client socket created" << endl;
}
cout << "Initialization succeeded." << endl << endl << endl;
return 105;
}
/**
Creates the connexion to TCP
@param none
@return an int to get the exit point of the function
*/
int CmTcpTransport::connectTcp()
{
if (m_nTcpMode == 1) // SERVER
{
cout << "Waiting for connexion..." << endl;
int clientLen(0);
clientLen = sizeof(clientaddr);
if ((clientSocket = accept(serverSocket, (SOCKADDR *)&clientaddr, &clientLen) == INVALID_SOCKET))
{
cout << "SERVER: Connexion failed." << endl;
return 202;; // Couldn't listen
}
else {
cout << "SERVER: Connexion established." << endl << endl << endl;
if (clientSocket == SOCKET_ERROR)
{
printf("socket became invalid after connexion:: %d\n", WSAGetLastError());
}
else {
cout << "SOCKET STILL VALID AND WORKING AFTER CONNEXION" << endl;
}
return 201;
}
}
else // CLIENT
{
cout << "Connecting..." << endl;
if (connect(clientSocket, (SOCKADDR *)&serveraddr, sizeof(serveraddr)) == SOCKET_ERROR)
{
cout << "CLIENT: Connexion failed." << endl << endl << endl;
return 202;; // Couldn't connect
}
else
{
cout << "CLIENT: Connexion to server succeeded." << endl << endl << endl;
}
return 203;
}
}
/**
Receives a buffer of bytes from the TCP
@param buffer: buffer to store the data
bufLen: size of the buffer
@return nbChar: the result of the recv function
if no error occurs, recv returns the number of bytes received
else, it returns a value of SOCKET_ERROR
*/
int CmTcpTransport::recvTcp(char *buffer, int bufLen)
{
if (clientSocket == SOCKET_ERROR)
{
printf("socket became invalid before receive:: %d\n", WSAGetLastError());
}
else {
cout << "SOCKET STILL VALID AND WORKING BEFORE RECEIVE" << endl;
}
int nbChar = recv(clientSocket, buffer, bufLen, 0);
if (nbChar == SOCKET_ERROR)
{
printf("recv failed: %d\n", WSAGetLastError());
cout << "No data received." << endl << endl << endl;
return nbChar;
}
else {
buffer[nbChar]=0; // Gestion de la taille du buffer
cout << "Data received: " << buffer << endl << endl << endl;
return nbChar;
}
}
/**
Sends a buffer of bytes to the TCP
@param buffer: buffer containing the data
bufLen: size of the buffer
@return nbChar: the result of the send function
if no error occurs, recv returns the number of bytes sent
else, it returns a value of SOCKET_ERROR
*/
int CmTcpTransport::sendTcp(char *buffer, int bufLen)
{
int nbChar = send(clientSocket, buffer, bufLen,0);
if (nbChar == SOCKET_ERROR)
{
cout << "No data sent." << endl << endl << endl;
return nbChar;
}
else {
cout << "Data sent: " << buffer << endl << endl << endl;
return nbChar;
}
}
server main.cpp
int main(int argc, char* argv[])
{
// ----------------------- WINSOCK ----------------------------
cout << "Initializing winsock library..." << endl;
// Start up Winsock
WSADATA wsadata;
int error = WSAStartup(0x101, &wsadata);
// Error ?
if (error) 0;
// Try Winsock Version ?
if (wsadata.wVersion != 0x101)
{
WSACleanup(); // Clean up Winsock
return 101;
}
cout << "Initialization successful" << endl << endl << endl;
// ----------------------- SERVER ---------------------------
char buffer[3000];
int testRecv; // return of the recv function
cout << "SERVER" << endl << endl << endl;
// Simulate the activity of the TcpListener transfering a listening Socket for the client connexion
SOCKET testSocket;
testSocket = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
// Creating a new TCP transport
CmTcpTransport server;
// Initialize and connect the TCP transport
server.initialize("127.0.0.1", 10000, testSocket, TTCP_MODE_SERVER);
server.connectTcp();
// Try to receive data
testRecv = server.recvTcp(buffer, sizeof(buffer));
cout << testRecv << endl;
// Disconnect
server.disconnectTcp();
return 0;
}
client main.cpp
int main(int argc, char* argv[])
{
// ----------------------- WINSOCK ----------------------------
cout << "Initializing winsock library..." << endl;
// Start up Winsock
WSADATA wsadata;
int error = WSAStartup(0x0202, &wsadata);
// Error ?
if (error) 0;
// Try Winsock Version ?
if (wsadata.wVersion != 0x0202)
{
WSACleanup(); // Clean up Winsock
return 101;
}
cout << "Initialization successful" << endl << endl << endl;
// ----------------------- CLIENT ---------------------------
char buffer[10000];
cout << "CLIENT" << endl << endl << endl;
// this Socket won't be used as the TCP transport is in client mode
SOCKET test;
test = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
// Create, initialize and connect the client TCP transport
CmTcpTransport client;
client.initialize("127.0.0.1", 10000, test, TTCP_MODE_CLIENT);
client.connectTcp();
// Copy the data in the buffer and send it
strcpy(buffer, "Test donnees");
client.sendTcp(buffer, sizeof(buffer));
client.disconnectTcp();
return 0;
}
And here are screenshots of my consoles when I run both mains:
http://www.hostingpics.net/viewer.php?id=892752Consoles.jpg
Thank you for your help, I realize this is a lot to read/process and I appreciate the effort !
I think you are invalidating the new sock-id on accept
with incorrect braces :
if ((clientSocket = accept(serverSocket, (SOCKADDR *)&clientaddr, &clientLen) == INVALID_SOCKET))
Try changing it to :
if ((clientSocket = accept(serverSocket, (SOCKADDR *)&clientaddr, &clientLen)) == INVALID_SOCKET)