Problem with my Winsock application

  • (2 Pages)
  • +
  • 1
  • 2

24 Replies - 1640 Views - Last Post: 15 April 2015 - 10:12 PM Rate Topic: -----

#1 odysseyofnoises   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 18
  • Joined: 07-March 15

Problem with my Winsock application

Posted 11 April 2015 - 10:01 PM

I am building a basic chat room application using Winsock for the network code. The problem is that when I try to host the server using my public ip address, it does not work because it claims that a user has connected right after it creates the listen socket. It works fine if I use the local ip address of my computer, but how do I make it so that I can host the server using my public ip so that a remote user could connect?

Here is the full code of my program:

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

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN

#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <Windows.h>
#include <string>
#include <new>

using namespace std;

int main()
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);
	
	cout << "Main menu:\n\n";
	cout << "1) Create room\n";
	cout << "2) Join room\n";
	
	string option;
	cin >> option;

	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);

	cout << "\nChoose a username: ";

	string username;
	cin >> username;

	WSADATA wsa;
	WSAStartup(MAKEWORD(2, 3), &wsa);

	SOCKADDR_IN address;
	int addressSize = sizeof(address);

	string sentMessage;
	string* receivedMessage;
	
	char buffer[255];

	if (option == "1")
	{
		SOCKET listenSocket = INVALID_SOCKET;
		SOCKET serverSocket = INVALID_SOCKET;

		serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

		address.sin_addr.s_addr = inet_addr("<public ip string>");
		address.sin_port = htons(444);
		address.sin_family = AF_INET;

		listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

		bind(listenSocket, (SOCKADDR*)&address, sizeof(address));
		listen(listenSocket, SOMAXCONN);

		cout << "\nWaiting...\n";

		while (true)
		{
			if (serverSocket = accept(listenSocket, (SOCKADDR*)&address, &addressSize))
				cout << "\nA user has connected. Send /disconnect at any time to leave.\n\n";

			closesocket(listenSocket);

			break;
		}
		
		cin.ignore();
		
		while (true)
		{
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);

			cout << "<" << username << ">  ";

			getline(cin, sentMessage);

			if (sentMessage == "/disconnect")
			{
				send(serverSocket, "/disconnect", 12, NULL);

				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);

				closesocket(serverSocket);

				goto end;
			}
			
			sentMessage = "<" + username + ">  " + sentMessage;

			for (int i = 0; i <= sentMessage.length(); i++)
				buffer[i] = sentMessage[i];

			send(serverSocket, buffer, sizeof(buffer), NULL);

			if (recv(serverSocket, buffer, sizeof(buffer), NULL) != 0)
			{	
				receivedMessage = new string(buffer);
				
				if (*receivedMessage == "/disconnect")
				{
					SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);

					cout << "\nOther user disconnected.\n";
					
					closesocket(serverSocket);

					goto end;
				}

				cout << '\a' << buffer << endl;
			}
		}
	}

	if (option == "2")
	{
		SOCKET clientSocket = INVALID_SOCKET;

		clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

		address.sin_addr.s_addr = inet_addr("<public ip string>");
		address.sin_port = htons(444);
		address.sin_family = AF_INET;

		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);

		if (connect(clientSocket, (SOCKADDR*)&address, sizeof(address)) == 0)
			cout << "\nConnected. Send /disconnect at any time to leave.\n\n";
		
		cin.ignore();
		
		while (true)
		{
			if (recv(clientSocket, buffer, sizeof(buffer), NULL) != 0)
			{	
				receivedMessage = new string(buffer);

				if (*receivedMessage == "/disconnect")
				{
					SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);

					cout << "\nOther user disconnected.\n";

					closesocket(clientSocket);

					goto end;
				}
				
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);

				cout << '\a' << buffer << endl;

				cout << "<" << username << ">  ";

				getline(cin, sentMessage);

				if (sentMessage == "/disconnect")
				{
					send(clientSocket, "/disconnect", 12, NULL);

					SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);

					closesocket(clientSocket);
					
					goto end;
				}
				
				sentMessage = "<" + username + ">  " + sentMessage;

				for (int i = 0; i <= sentMessage.length(); i++)
					buffer[i] = sentMessage[i];
				
				send(clientSocket, buffer, sizeof(buffer), NULL);
			}
		}
	}

end:

	WSACleanup();

	cout << endl; system("pause");

	return 0;
}



Is This A Good Question/Topic? 0
  • +

Replies To: Problem with my Winsock application

#2 Salem_c   User is offline

  • void main'ers are DOOMED
  • member icon

Reputation: 2386
  • View blog
  • Posts: 4,522
  • Joined: 30-May 10

Re: Problem with my Winsock application

Posted 11 April 2015 - 10:52 PM

Some thoughts.

1. Install wireshark, so you know what's happening on the network.

2. Restructure your code so you don't have a massively long main() function. This will allow you to cleanly remove all those goto's for example.

> address.sin_port = htons(444);
3. Port 444 is a reserved port, and being <= 1024, likely to be aggressively blocked by firewalls.
http://www.iana.org/...s.xhtml?&page=8
Pick a port number in the appropriate range for your application.

4. You blindly assume that x = send(clientSocket, "/disconnect", 12, NULL); x will always be 12. This is not true. x could be ANY number >= 1 and <= 12, and it would still count as a successful send. YOU need to arrange to retry the unsent data. The same goes for recv(). Assume in the worst case that recv() manages to fetch only one byte at a time over a particularly slow and error prone remote link.
Was This Post Helpful? 0
  • +
  • -

#3 odysseyofnoises   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 18
  • Joined: 07-March 15

Re: Problem with my Winsock application

Posted 12 April 2015 - 11:49 AM

I changed my port to 5555 and tried installing wireshark, then hosting the server on my public ip, but I did not even see any entries in wireshark for port 5555. I tried testing if each socket is being created correctly, and it appears that the socket called serverSocket is not being created correctly. The "Error" message will get printed in the code below.

this is the relevant bit of code (the part that checks if a user has connected):

while (true)
		{
		        if (serverSocket = accept(listenSocket, (SOCKADDR*)&address, &addressSize))
				cout << "\nA user has connected. Send /disconnect at any time to leave.\n\n";
			
			if (serverSocket == INVALID_SOCKET)
				cout << "\nError.\n";

			closesocket(listenSocket);

			break;
		}


Was This Post Helpful? 0
  • +
  • -

#4 snoopy11   User is offline

  • Engineering ● Software
  • member icon

Reputation: 1556
  • View blog
  • Posts: 4,930
  • Joined: 20-March 10

Re: Problem with my Winsock application

Posted 12 April 2015 - 12:44 PM

You don't use the curly bracket { and } around your first if statement.

I would suggest you do so as you are probably breaking from your loop too quickly.

Regards

Snoopy.
Was This Post Helpful? 0
  • +
  • -

#5 BBeck   User is offline

  • Here to help.
  • member icon


Reputation: 792
  • View blog
  • Posts: 1,886
  • Joined: 24-April 12

Re: Problem with my Winsock application

Posted 12 April 2015 - 02:07 PM

It's been forever and a day since I've messed with WinSock. I did a couple clients and servers and such. I think I even did one in UNIX. But the main one I did was a chat server and a chat client with a couple of specialized features. That was all Win32 rather than a console app. So, it's been even longer since I tried to do blocking sockets as a console app.

But, as I recall, you have to setup a listening socket on a given TCP port. When the call comes in, you have to tell it to call back in on a different port you spin up and then you hang up on them. At that point, you can go back to listening on the original port again. The new port answers and you have a connection. Seems to me though, you would have to do multi-threading to listen and communicate at the same time, especially with more than one client but again it's been forever since I've done it. In Win32 that's not a big deal because every thing is event driven and you're in a constant loop anyway.

But I would have to go build a test app to even tell you how it works anymore.

TelNet is great for using as a test client until you build your own server and then once you have that mastered build your own client.
Was This Post Helpful? 0
  • +
  • -

#6 odysseyofnoises   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 18
  • Joined: 07-March 15

Re: Problem with my Winsock application

Posted 12 April 2015 - 02:08 PM

Oh, yeah, I noticed that problem and fixed it, but it doesn't make a difference for my problem of not being able to host a server with my public ip address.

The serverSocket is still not being created correctly, even though it is if I use my local ip. I have port forwarding set up correctly, also.

The code is now this:

while (true)
		{
			if (serverSocket = accept(listenSocket, (SOCKADDR*)&address, &addressSize))
			{
				cout << "\nA user has connected. Send /disconnect at any time to leave.\n\n";

				closesocket(listenSocket);

				break;
			}
		}


Was This Post Helpful? 0
  • +
  • -

#7 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7087
  • View blog
  • Posts: 24,090
  • Joined: 05-May 12

Re: Problem with my Winsock application

Posted 12 April 2015 - 06:32 PM

if (serverSocket = accept(listenSocket, (SOCKADDR*)&address, &addressSize))



This statement will always be true for both when a connection is successful and when a connection fails. This is because the return value INVALID_SOCKET is defined to be non-zero.
Was This Post Helpful? 1
  • +
  • -

#8 odysseyofnoises   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 18
  • Joined: 07-March 15

Re: Problem with my Winsock application

Posted 12 April 2015 - 07:00 PM

Okay, I updated the code some more. At least now it doesn't show the "a user has connected" message when the serverSocket fails. However, the problem still stands that I can't get it to work with my public ip address.

while (true)
		{
			serverSocket = accept(listenSocket, (SOCKADDR*)&address, &addressSize);

			if (serverSocket != INVALID_SOCKET)
			{
				cout << "\nA user has connected. Send /disconnect at any time to leave.\n\n";

				closesocket(listenSocket);

				break;
			}
		}


Was This Post Helpful? 0
  • +
  • -

#9 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7087
  • View blog
  • Posts: 24,090
  • Joined: 05-May 12

Re: Problem with my Winsock application

Posted 12 April 2015 - 07:16 PM

You cannot use your public IP address because there is no way for your computer to configure the port on the machine/device that has the public address for listening. Think about it. You are using Winsock. How do you expect it a Windows API to magically work on your router that is likely running on a stripped down version of Linux? Or if you happen to be tethering to a cellphone, how will Windows magically get your Android or iOS phone to open up a port for listening?

What you need to do is listen on your private IP address and just ensure that your public facing device (router, cell phone, etc.) is doing the correct port forwarding to your machine.
Was This Post Helpful? 0
  • +
  • -

#10 odysseyofnoises   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 18
  • Joined: 07-March 15

Re: Problem with my Winsock application

Posted 12 April 2015 - 07:50 PM

Now I think I might be getting somewhere, but it's not exactly where I want to be...

Now, when I try to connect as a client, I receive some gibberish data and then when I send a message, it just echoes it back to me. The server is supposed to be the first one to send a message, and it appears that it did send a gibberish message, but how could it if the server's console window still says "waiting..."? It's all a bit weird.

I have a screenshot taken of the client's view since it's kind of difficult to explain.

Screenshot: http://postimg.org/image/evx83asfj/
Was This Post Helpful? 0
  • +
  • -

#11 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7087
  • View blog
  • Posts: 24,090
  • Joined: 05-May 12

Re: Problem with my Winsock application

Posted 12 April 2015 - 07:59 PM

Post your updated code.
Was This Post Helpful? 0
  • +
  • -

#12 odysseyofnoises   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 18
  • Joined: 07-March 15

Re: Problem with my Winsock application

Posted 12 April 2015 - 08:15 PM

Oh, yeah, I was actually considering doing that.

I will remove the goto statements and stuff when I get the program to function on a basic level. That shouldn't matter right now anyway since they're just used to go to the end of the program.

Here's the full updated code to account for all of the changes:

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

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN

#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <Windows.h>
#include <string>
#include <new>

using namespace std;

int main()
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);
	
	cout << "Main menu:\n\n";
	cout << "1) Create room\n";
	cout << "2) Join room\n";
	
	string option;
	cin >> option;

	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);

	cout << "\nChoose a username: ";

	string username;
	cin >> username;

	WSADATA wsa;
	WSAStartup(MAKEWORD(2, 3), &wsa);

	SOCKADDR_IN address;
	int addressSize = sizeof(address);

	string sentMessage;
	string* receivedMessage;
	
	char buffer[255];

	if (option == "1")
	{
		SOCKET listenSocket = INVALID_SOCKET;
		SOCKET serverSocket = INVALID_SOCKET;

		serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

		address.sin_addr.s_addr = inet_addr("192.168.1.25");
		address.sin_port = htons(5555);
		address.sin_family = AF_INET;

		listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

		bind(listenSocket, (SOCKADDR*)&address, sizeof(address));
		listen(listenSocket, SOMAXCONN);

		cout << "\nWaiting...\n";

		while (true)
		{
			serverSocket = accept(listenSocket, (SOCKADDR*)&address, &addressSize);

			if (serverSocket != INVALID_SOCKET)
			{
				cout << "\nA user has connected. Send /disconnect at any time to leave.\n\n";

				closesocket(listenSocket);

				break;
			}
		}
		
		cin.ignore();
		
		while (true)
		{
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);

			cout << "<" << username << ">  ";

			getline(cin, sentMessage);

			if (sentMessage == "/disconnect")
			{
				send(serverSocket, "/disconnect", 12, NULL);

				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);

				closesocket(serverSocket);

				goto end;
			}
			
			sentMessage = "<" + username + ">  " + sentMessage;

			for (int i = 0; i <= sentMessage.length(); i++)
				buffer[i] = sentMessage[i];

			send(serverSocket, buffer, sizeof(buffer), NULL);

			recv(serverSocket, buffer, sizeof(buffer), NULL);
	        
			receivedMessage = new string(buffer);
				
			if (*receivedMessage == "/disconnect")
			{
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);

				cout << "\nOther user disconnected.\n";
					
				closesocket(serverSocket);

				goto end;
			}

			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE);

			cout << '\a' << buffer << endl;
		}
	}

	if (option == "2")
	{
		SOCKET clientSocket = INVALID_SOCKET;

		clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

		address.sin_addr.s_addr = inet_addr("71.21.189.199");
		address.sin_port = htons(5555);
		address.sin_family = AF_INET;

		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);

		if (connect(clientSocket, (SOCKADDR*)&address, sizeof(address)) == 0)
			cout << "\nConnected. Send /disconnect at any time to leave.\n\n";
		
		cin.ignore();
		
		while (true)
		{
			recv(clientSocket, buffer, sizeof(buffer), NULL);

			receivedMessage = new string(buffer);

			if (*receivedMessage == "/disconnect")
			{
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);

				cout << "\nOther user disconnected.\n";

				closesocket(clientSocket);

				goto end;
			}

			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE);
				
			cout << '\a' << buffer << endl;

			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);

			cout << "<" << username << ">  ";

			getline(cin, sentMessage);

			if (sentMessage == "/disconnect")
			{
				send(clientSocket, "/disconnect", 12, NULL);

				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);

				closesocket(clientSocket);

				goto end;
			}

			sentMessage = "<" + username + ">  " + sentMessage;

			for (int i = 0; i <= sentMessage.length(); i++)
				buffer[i] = sentMessage[i];

			send(clientSocket, buffer, sizeof(buffer), NULL);
		}
	}

end:

	WSACleanup();

	cout << endl; system("pause");

	return 0;
}


Was This Post Helpful? 0
  • +
  • -

#13 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7087
  • View blog
  • Posts: 24,090
  • Joined: 05-May 12

Re: Problem with my Winsock application

Posted 12 April 2015 - 08:32 PM

How do you know if your send()'s and recv()'s are successful if you are ignoring their return values? You seem to just assume that they succeed just like you are assuming that your bind(), listen(), and other calls will succeed.
Was This Post Helpful? 0
  • +
  • -

#14 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7087
  • View blog
  • Posts: 24,090
  • Joined: 05-May 12

Re: Problem with my Winsock application

Posted 12 April 2015 - 08:39 PM

Anyway, did you actually attach a debugger to your server and ensure that you are still "waiting"? It's quite possible the output on line 82 is not visible on the console yet because the console has not been flushed because it has not yet encountered a newline.

The "junk" that you are seeing is very likely the result of a failed reception on line 144 and you are blindly printing it out on line 161.

Also, as general comment, you seem to be sending messages back and forth, but you are not sending the null terminator. On the receiving side, you assume that message is null terminated. If you got a failure like on line 144, the buffer will be uninitialized and you could very easily do a buffer overrun when you try to copy the buffer on line 146. Once you do a buffer overrun, all bets are off because you have invoked undefined behavior. The computer is free to do what it pleases when you invoke undefined behavior -- including acting randomly.

You should really break up your code into multiple functions. It'll make the code much easier to read and would simplify things so that you don't need those silly goto's.
Was This Post Helpful? 1
  • +
  • -

#15 odysseyofnoises   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 18
  • Joined: 07-March 15

Re: Problem with my Winsock application

Posted 12 April 2015 - 09:39 PM

I just tried to run the client part without there being a server running, and it still has the same behavior as before. So then it's not because it's receiving something bad, since the server isn't even running to send anything. I think that the client is just not connecting correctly, then. That's strange, since I'm sure I have port forwarding set up to the correct address.
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2