Skip to main content
gamedev.net
🔒 Locked

Problems getting started...

Started by TerranFury 6 replies 2.4k views
Original Post
TerranFury
TerranFury
I have never coded anything involving networking or multiplayer before, but I wanted to try. So I read some of the articles here on gamedev, looking for basic tutorials on programming using winsock. I found some, and they were useful. However, I figured I'd try to code something very simple, and it doesn't work. The idea was this. The program gives you two options, client and server. As a server, you wait for 1 client to connect. You then receive a prompt asking for a text string. Enter it, and it is sent to the client. Done. As a client, you connect to the server (connecting to localhost is hard-coded in) and wait for a message from the server. When you receive it, display it. Done. The program uses a blocking server and TCP/IP. Or at least that's how it's supposed to work. Instead, what happens is this: I start one instance of the program, and tell it to be a server. It waits. Then I start a second instance, and tell it to be a client. It waits. However, the prompt has now appeared on the server asking for the string. I enter it, and the program finishes. I then check the client. It has just output a bunch of characters to the screen, and the program is now done. So far, everything sounds like its supposed to. However, the characters that I get on the client are not the characters that I input on the server. In fact, when I step through that section of the code, the contents of the buffer before my recv(...) call are exactly the same as after it. Something, obviously, is wrong. I'm about to paste the code here, and I understand it's a little much. Hopefully, though, somebody (you?) can point out my mistake. Chances are it's pretty simple.
          


#pragma comment (lib, "ws2_32.lib")

#include <winsock2.h>
#include <windows.h>


#include <string.h>

//#include <conio.h>


#include <iostream>
using namespace std;

const int PORT_NUM = 5513; //I just arbitrarily chose this

const int BUFFER_SIZE = 128;



bool initWinsock()
{
	WSADATA w;    // used to store information about WinSock version

	int error = WSAStartup (0x0202, &w);   // Fill in w


	if (error)
	{ // there was an error

	  return false;
	}
	if (w.wVersion != 0x0202)
	{ // wrong WinSock version!

	  WSACleanup (); // unload ws2_32.dll

	  return false;
	}

	return true;
}

int server()
{
		cout << "SERVER\n";

		const int MAX_CLIENTS = 1;

		// Create socket:

		//	SOCK_STREAM = TCP

		//	SOCK_DGRAM	= UDP

		SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (s == INVALID_SOCKET)
		{
			cout << "Could not create socket.\n";
			return 1;
		}



		//Bind socket (only for servers)

		sockaddr_in addr;				// the address structure for a TCP socket

		addr.sin_family = AF_INET;      // Address family Internet

		addr.sin_port = htons (PORT_NUM);   // Assign port 80 to this socket

		addr.sin_addr.s_addr = htonl (INADDR_ANY);   // No destination

		if (bind(s, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
		{ // error

			cout << "Could not bind socket.\n";
			return 1;         // quit

		}


		//Server: Listen to port

		if (listen(s,MAX_CLIENTS)==SOCKET_ERROR)
		{
			// error!  unable to listen

			cout << "Could not listen to port.\n";
			return 1;
		}

		//Wait for client and accept him:

		SOCKET client;			// socket handles to clients

		sockaddr client_sock;	// info on client sockets

		int addr_size = sizeof(client_sock);

		client = 
			accept (s, &client_sock, &addr_size);
			
		if (client == INVALID_SOCKET)
		{
			// error accepting connection

			cout << "Could not accept connection\n";
			return 1;
		}
		else
		{
			// start a thread that will communicate with client

		}


		//Accept and send data


		char buffer[BUFFER_SIZE];
		cout << "Enter any string: ";
		cin >> buffer;
		//Send data:

		if(send (s, buffer, strlen(buffer), 0) == SOCKET_ERROR)
		{
			cout	<< "Error sending.\nError code: "
					<< WSAGetLastError();
			return 1;
		}


		shutdown (s, SD_SEND);  // s cannot send anymore

		// you should check to see if any last data has arrived here

		closesocket (s);   // close


		return 0;
}

int client()
{
			cout << "CLIENT\n";

		//Create client socket

		SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP );
		if(s == INVALID_SOCKET)
		{
			cout << "Could not create socket.\n";
			return 1;
		}

		
		//Try to connect with socket s

		sockaddr_in target;

		target.sin_family = AF_INET;           // address family Internet

		target.sin_port = htons (PORT_NUM);        // set server’s port number

		target.sin_addr.s_addr = inet_addr ("127.0.0.1");  // set server’s IP (originally 52.123.72.251)


		if (connect(s, (LPSOCKADDR)⌖, sizeof(target)) == SOCKET_ERROR)
		{
			// an error connecting has occurred!

			cout << "Could not connect\n.";
			return 1;
		}


		//Receive data

		char buffer2[BUFFER_SIZE];
		Sleep(100);
		if(recv (s, buffer2, sizeof(buffer2), 0) == SOCKET_ERROR)
		{
			cout	<< "Error receiving.\nError code: "
					<< WSAGetLastError();
			return 1;
		}

		cout << buffer2 << endl;

		shutdown (s, SD_RECEIVE);  // s cannot receive anymore

		// you should check to see if any last data has arrived here

		closesocket (s);   // close


		return 0;
}

int main()
{
	if(!initWinsock())
	{
		cout << "Could not initialize winsock\n";
		return 1;
	}

	int choice;
	cout <<  "Client (1) or server (0)? ";
	cin >> choice;

	if(choice == 0)
		server();
	else if(choice == 1)
		client();


	WSACleanup();

	return 0;
}

    
Any help would be greatly appreciated. Thanks in advance. Edited by - TerranFury on January 18, 2002 9:38:10 PM
johnnie2
johnnie2
Use sizeof() instead of strlen() to determine the length of the send and receive buffers.
____________"Optimal decisions, once made, do not need to be changed." - Robert Sedgewick, Algorithms in C
TerranFury
TerranFury
I figured I could send a smaller amount of data if I sent only up to the end of the string. I was receiving an amount equal to the size of my receiving buffer. I figured that would work. It probably would. However, I tried using sizeof(), as you suggested, and it didn''t solve my problem. I''m using sizeof() now, but that doesn''t seem to be the source of my problem. Any ideas as to what could be?
Shannon Barber
Shannon Barber
Try putting IPPROTO_TCP in for the last parameter of the socket()... I don't know if it's essential, but it won't hurt if it's not.


sockaddr client_sock; // info on client sockets
int addr_size = 128; // I just arbitrarily chose this.

Ack!
int addr_size = sizeof(client_sock);

Keep using strlen to determine how much data to send; zero the recv buffer2 before you use it (so there'll be null-terminator where you need one).

Put a Sleep(100) in right before the call to Recv, and check it's return code! Check the send's return code too.

Edited by - Magmai Kai Holmlor on January 17, 2002 8:31:17 PM
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
TerranFury
TerranFury
Thanks Magmai Kai Holmlor for the tips. I had actually fixed that arbitrary 128 thing between my first post and your response. I used your other suggestions.

I got error 10057 on the server when trying to send. I looked in the header, and that seems to be WSAENOTCONN. The documentation gives the following explanation:
The socket is not connected.

I got error 10054 on the client when trying to recv. Again I looked in the header, and this error seems to be WSAECONNRESET. The documentation gives the following explanation:
The virtual circuit was reset by the remote side executing a "hard" or "abortive" close. For UPD sockets, the remote host was unable to deliver a previously sent UDP datagram and responded with a "Port Unreachable" ICMP packet. The application should close the socket as it is no longer usable.

I still don''t know what''s wrong or how to fix it, but I have a feeling we''re getting on the right track now (I hope).
TerranFury
TerranFury
Note: I edited my first post. It now contains the newest code.
Dire.Wolf
Dire.Wolf
Try sending the data using the client socket:

if(send (s, buffer, strlen(buffer), 0) == SOCKET_ERROR)

---------^ // oops - should be client (socket)

BTW You got the 10057 (Not Connected Error) on the server because you were trying to send data on the listening server socket.

When the call to send() fails, your program exits and Windows cleans up you client and server socket handles once the process exits. Windows doesn't clean them up nicely either...

On the client side you receive the 10054 error (connection reset) because that is truly what happened. Windows just killed the kernel object representing the other end of the client connection (from the now non-existant server) and poof! Connection reset.

Something you need to check for on the client is graceful closes. When a server closes a connected socket gracefully (via shutdown/closesocket), recv() will return with 0 not SOCKET_ERROR.

So:


int result = recv(s, buffer, sizeof(buffer), 0);
if(result == 0)
{
// connection closed
}
else if(result == SOCKET_ERROR)
{
// call GetLastError() etc.
}


As you said, it is probably something simple...

(Hopefully I'm right...



Dire Wolf
www.digitalfiends.com

Edited by - Dire.Wolf on January 18, 2002 12:56:31 AM
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
TerranFury
TerranFury
Thank you very much Dire.Wolf! It works perfectly. Now I can move on to bigger and better things.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.