Sign in to follow this  
BennettSteele

C++ Winsock Connecting to an IP Address Problem

Recommended Posts

So i finished the networking code on the same machine (the client connects to IP 127.0.0.1), and it works perfectly, but then when i tried giving it the another person, it didnt connect. i was wondering if the ip on the machine can be used to connect... also, we use hamachi, so when i gave him that ip it still didnt work. is there something i need to know about connecting different machines? PS: im using TCP sockets.

Share this post


Link to post
Share on other sites
Sorry, whoops. :-\

What do you mean by initializing?

ServerStats.h:
[code]#include <string>
#include <vector>
#include <Winsock2.h>
#include <Windows.h>
class Client_Sock
{
public:
SOCKET mSock;
std::string Ip;
unsigned int Id,Ping,ThreadKillState;
bool OK;
HANDLE mThread;
void New(SOCKET nSock,std::string nIp,unsigned int nID);
void Die();
};
class ServerStats
{
public:
bool Host,Connected,Connecting;
std::vector<Client_Sock> ConnectedIPs;
SOCKET MySocket;
WSADATA nData;
SOCKADDR_IN Target;//Socket address information
std::string DefaultIP,IPConnectedTo;
int DefaultPort,PortConnectedTo;
HANDLE mThread;
unsigned int Ping,ThreadKillState,LastSecond;

void Init(bool nHost);
void Restart();
void Quit();
unsigned int ErrorID;

bool LastError(std::string What);
void Connect(std::string nHost,int Port);
void DisConnect();
void Listen(int PortNO);
void Send(std::string What,int Who);
void HandleMessage(std::string Mess,std::string Plr);
void CheckPings();
void Kill_Sock(unsigned int Sock);

unsigned int ReadyToStartGame;
};
DWORD WINAPI ListenForNew(void*);
DWORD WINAPI HandleNewConnection(void*);
DWORD WINAPI ConnectToHost(void*);
[/code]

ServerStats.cpp:
[code]#include "ServerStats.h"
#include "App.h"
extern myApp APP;
#include "Functions.h"
#define REC_MAX 1024
void Client_Sock::New(SOCKET nSock,std::string nIp,unsigned int nID)
{
Client_Sock::mSock=nSock;
Client_Sock::Ip=nIp;
Client_Sock::Id=nID;
Client_Sock::OK=true;
Client_Sock::Ping=0;
Client_Sock::ThreadKillState=0;//None
unsigned int nErr=WSAGetLastError();
if(nErr!=0)
{
LPTSTR Error=0;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,NULL,nErr,0,(LPTSTR)&Error,0,NULL);
std::stringstream nError;nError<<"WSA Sync Socket Error: "<<nErr<<", "<<Error;
APP.ServerLog.Write((nError.str()).c_str());
}
Client_Sock::mThread=CreateThread(NULL,0,HandleNewConnection,(void*)nID,0,NULL);
}
void Client_Sock::Die()
{
Client_Sock::OK=false;
Client_Sock::ThreadKillState=1;
TerminateThread(Client_Sock::mThread,0);
closesocket(Client_Sock::mSock);
}
void ServerStats::Init(bool nHost)
{
unsigned int nErr=WSAStartup(MAKEWORD(2,2),&this->nData);
if(nErr!=0)
{
LPTSTR Error=0;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,NULL,nErr,0,(LPTSTR)&Error,0,NULL);
std::stringstream nError;nError<<"WSA Startup Error: "<<nErr<<", "<<Error;
APP.ServerLog.Write((nError.str()).c_str());
}
ServerStats::DefaultIP="5.14.221.173";
ServerStats::DefaultPort=31316;
ServerStats::Host=nHost;
this->LastSecond=APP.LastSecond;
this->ErrorID=0;
this->ReadyToStartGame=0;
ServerStats::MySocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(this->LastError("Socket"))
{
this->DisConnect();
}
ServerStats::Connected=false;
ServerStats::Connecting=false;
}
void ServerStats::Restart()
{
this->LastSecond=APP.LastSecond;
ServerStats::MySocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(this->LastError("Socket"))
{
this->DisConnect();
}
ServerStats::Connected=false;
ServerStats::Connecting=false;
}
void ServerStats::Quit()
{
if(this->Connected || this->Connected)
{
this->DisConnect();
}
closesocket(ServerStats::MySocket);
WSACleanup();
}
bool ServerStats::LastError(std::string What)
{
this->ErrorID=WSAGetLastError();
if(this->ErrorID!=0)
{
LPTSTR Error=0;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,NULL,this->ErrorID,0,(LPTSTR)&Error,0,NULL);
std::stringstream nError;nError<<What+" Error: "<<this->ErrorID<<", "<<Error;
APP.ServerLog.Write((nError.str()).c_str());
return true;
}
else
{
return false;
}
}
#include "App.h"
extern myApp APP;
#include "GameStats.h"
extern GameStats Game;
extern ServerStats Server;
#include "ScreenClass.h"
extern Screen MainScreen;
void ServerStats::Connect(std::string nHost,int Port)
{
if(!this->Host && !this->Connected && !this->Connecting)//first
{
this->Restart();
this->Connecting=true;
this->IPConnectedTo=nHost;
this->PortConnectedTo=Port;
ServerStats::Target.sin_family=AF_INET;
ServerStats::Target.sin_port=htons(Port);
ServerStats::Target.sin_addr.s_addr=inet_addr(nHost.c_str());
if(this->mThread==NULL)//Have not started thread
{
this->mThread=CreateThread(NULL,0,ConnectToHost,(void*)NULL,0,NULL);
}
}
else if(!this->Host && this->Connecting && !this->Connected)
{
connect(this->MySocket,(SOCKADDR*)&Target,sizeof(ServerStats::Target));
if(!this->LastError("Connect"))//no error
{
this->Connected=true;
this->Connecting=false;

newHuman Host;Host.Init(0,0,0,"client",0,"client",0,0,0);
Game.OnlinePlrs.push_back(Host);
if(this->ReadyToStartGame==0){this->ReadyToStartGame=1;}
}
}
else if(this->Host)
{
APP.ServerLog.Write("Tried To Connect When A Host");
}
else
{
APP.ServerLog.Write("Tried To Connect When Already Connected");
}
}
void ServerStats::DisConnect()
{
shutdown(this->MySocket,SD_SEND);
if(this->Host)
{
for(unsigned int s=0;s<ServerStats::ConnectedIPs.size();s++)
{
ServerStats::Kill_Sock(s);
}
ServerStats::ConnectedIPs.clear();
}
else//not a host
{
ServerStats::ThreadKillState=1;//Class stuff
}
TerminateThread(this->mThread,0);
this->mThread=NULL;
this->Connected=false;
this->Connecting=false;
this->IPConnectedTo="0.0.0.0";
this->Ping=0;
this->PortConnectedTo=0;
this->ThreadKillState=0;
this->ErrorID=0;
}
void ServerStats::Listen(int PortNO)
{
if(this->Host && !this->Connected)
{
this->Restart();
this->Connected=true;
ServerStats::Target.sin_family=AF_INET;
ServerStats::Target.sin_port=htons(PortNO);//assign port to this socket
ServerStats::Target.sin_addr.s_addr=inet_addr("127.0.0.1");
bind(ServerStats::MySocket,(LPSOCKADDR)&this->Target,sizeof(ServerStats::Target));
listen(this->MySocket,1);
if(this->mThread==NULL)//Have not started thread
{
this->mThread=CreateThread(NULL,0,ListenForNew,(void*)NULL,0,NULL);
}
}
else if(!this->Host)
{
APP.ServerLog.Write("Tried To Listen When NOT A Host");
}
else if(this->Connected)
{
APP.ServerLog.Write("Tried To Listen When Listening");
}
}
void ServerStats::Send(std::string What,int Who)
{
if(ServerStats::Host)
{
if(Who==-1)//All clients
{
for(unsigned int s=0;s<ServerStats::ConnectedIPs.size();s++)
{
send(ServerStats::ConnectedIPs[s].mSock,What.c_str(),What.size(),0);
}
}
else if((unsigned int)Who<ServerStats::ConnectedIPs.size())
{
send(ServerStats::ConnectedIPs[Who].mSock,What.c_str(),What.size(),0);
}
}
else
{
send(ServerStats::MySocket,What.c_str(),What.size(),0);
}
}
void ServerStats::HandleMessage(std::string Mess,std::string Plr)
{
std::vector<std::string>mParts;
unsigned int State=0;
std::string Buf;
if(this->Host)
{
unsigned int PlrID=0;//No id
/*for(unsigned int nPlr=0;nPlr<Game.OnlinePlrs.size();nPlr++)
{
if(Game.OnlinePlrs[nPlr].Brain.Name==Plr)
{
PlrID=nPlr+1;
nPlr=Game.OnlinePlrs.size();
}
}*/
if(Game.OnlinePlrs.size()>0){PlrID=1;}
if(PlrID!=0)
{
PlrID--;
for(unsigned int l=0;l<Mess.length();l++)
{
if(State==5)
{
l=Mess.length();
}
else if(Mess[l]==',' || Mess[l]=='\\')
{
switch(State)
{
case 0:Game.OnlinePlrs[PlrID].myX=(float)atof(Buf.c_str());break;
case 1:Game.OnlinePlrs[PlrID].myY=(float)atof(Buf.c_str());break;
case 2:Game.OnlinePlrs[PlrID].myZ=(float)atof(Buf.c_str());break;

case 3:Game.OnlinePlrs[PlrID].RotX=(float)atof(Buf.c_str());break;
case 4:Game.OnlinePlrs[PlrID].RotY=(float)atof(Buf.c_str());break;
}
State++;
Buf.clear();
}
else
{
Buf+=Mess[l];
}
}
}
}
else
{
}
}
void ServerStats::CheckPings()
{
for(unsigned int s=0;s<ServerStats::ConnectedIPs.size();s++)
{
if(ServerStats::ConnectedIPs[s].Ping>10000)
{
ServerStats::Kill_Sock(s);
}
}
}
void ServerStats::Kill_Sock(unsigned int Sock)
{
if(Sock<ServerStats::ConnectedIPs.size())
{
ServerStats::ConnectedIPs[Sock].Die();
//Ready for class removal
ServerStats::ConnectedIPs.erase(ServerStats::ConnectedIPs.begin()+Sock);
}
}
DWORD WINAPI ListenForNew(void* LOL)
{
while(Server.ThreadKillState==0)
{
Client_Sock AcceptSock;
sockaddr_in nAddr;int nLength=sizeof(nAddr);
SOCKET defAccept=accept(Server.MySocket,(sockaddr*)&nAddr,&nLength);
AcceptSock.New(defAccept,inet_ntoa(nAddr.sin_addr),Server.ConnectedIPs.size());
Server.ConnectedIPs.push_back(AcceptSock);
newHuman nPlayer;nPlayer.Init(0,0,0,"client",0,"client",0,0,0);
Game.OnlinePlrs.push_back(nPlayer);

if(Server.ReadyToStartGame==0){Server.ReadyToStartGame=1;}
APP.ServerLog.Write(("New Client: "+AcceptSock.Ip).c_str());

}
Server.ThreadKillState=2;
ExitThread(0);
}
DWORD WINAPI HandleNewConnection(void* nID)
{
unsigned int ServerSendData=0,NextThousand=0;
int id=(int)nID;
while(Server.ThreadKillState==0)
{
std::string nMessage="hello from host";
Server.Send(nMessage,-1);
char Recieving[256];
int i=recv(Server.ConnectedIPs[id].mSock,Recieving,256,0);
if(i>0)
{
Recieving[i]='\0';
Server.HandleMessage(Recieving,"Client");
}
else if(i==0)
{
}//quit
else
{
if(Server.LastError("Recv"))
{
Server.DisConnect();
}
}
}
ExitThread(0);
}
DWORD WINAPI ConnectToHost(void* Param)
{
while(Server.ThreadKillState==0)
{
if(Server.Connected)
{
std::stringstream nMessage;
nMessage<<-Game.myX<<','<<Game.myY<<','<<-Game.myZ<<','<<Game.rotX<<','<<Game.rotY<<'\\';
Server.Send(nMessage.str().c_str(),0);

char Recieving[256];
int i=recv(Server.MySocket,Recieving,256,0);

if(i>0)
{
Recieving[i]='\0';
Server.HandleMessage(Recieving,"Client");
}
else if(i==0)
{
MainScreen.LoadScreen("play/online/choose");
APP.ServerLog.Write("Lost Connection");
}
else
{
if(Server.LastError("Recv"))
{
Server.DisConnect();
}
}
}
else if(Server.Connecting)
{
Server.Connect("",0);
}
}
ExitThread(0);
}[/code]

Im calling ServerStats::Init() at first, then in the next series of events, this is the order that things get called in (hopefully):

for host:
ServerStats::Disconnect();
ServerStats::Restart();//in to reset stuff
ServerStats::Listen();
ListenForNew();
(after new connection)
a new client is made, where Client_Sock::New() is called, then HandleNewConnection();

for client:
ServerStats::Disconnect()
ServerStats::Restart()//in to reset stuff
ServerStats::Connect()
ConnectToHost()


I just added breakpoints on all the functions... i dont know what could be wrong...

Share this post


Link to post
Share on other sites
That's connection refused. Typically that means either you have a firewall in the way or the server is not listening on the port you're attempting to connect to.

Share this post


Link to post
Share on other sites
Well, to be fair i did just test it on 1 other computer ( my friends ) and he had alot of antivirus stuff going on. since it works on a local computer that it *should* work on any other computer? Also, does error 10061 mean that the server is there, but it cant connect because there is a firewall? because i know for sure the host is listening, so it must be the client.

Share this post


Link to post
Share on other sites
10061, which a quick google or even just running win32 error would tell you, is WSAECONNREFUSED. All that means is that when the machine attempted to connect the remote machine refused the connection (actively in this case).

Testing on your local machine is fine, however it should be noted that firewalls do not monitor the localhost set of IPs (because they're local to the machine), so many such connection issues will not show up until you actually separate the client and server.

Share this post


Link to post
Share on other sites
Weird... so in this case... it would not be my application? possibly?

EDIT: im going to test on another computer that worked before with a different implementation of code...

Share this post


Link to post
Share on other sites
Do you have the firewall opened on the port in question, and port forwarding enabled on your router?
Also, I highly recommend reading the articles about NAT pointed at in the networking/multiplayer FAQ.

Share this post


Link to post
Share on other sites
With networking (and in general), it is a good idea to debug things by eliminating sources for error. You believe you have your program running correctly on a single machine.

Some ideas to diagnose connectivity issues:
[list]
[*] If you have a spare machine, try get it working on a local area network first, before trying it on the internet. This can remove external router configuration as a source of error.
[*] Your router might have a firewall too. I have had a home router where the firewall would block incoming connections, even when port forwarding was configured.
[*] Try turning off the local firewall on each of the machines (probably start with the server) in turn.
[*] Eliminate your code as a source of error by using existing, well tested client/server programs rather than your own one
[list]
[*] The built-in [i]telnet[/i] tool on Windows can be useful for TCP connections
[*] If you were using UDP, I'm not aware of any default tools but you can download UDP based programs to fill this gap
[*] The [i]ping[/i] tool can also help diagnose connectivity issues.
[/list]
[/list]
Obviously you should be careful when turning off firewalls - you are only doing this to diagnose whether the firewall configuration is causing the issue, you shouldn't require the user to disable firewalls to play or host your game.

Share this post


Link to post
Share on other sites
I found the problem yesterday:
I went to look at the example code, and where i bind the port, it is supposed to be "0.0.0.0", but i have a loopback address. /^3^\
the only problem now is that when the client joins, their application crashes. but thats for me to fix now! :P

Thanks for the help!

Share this post


Link to post
Share on other sites
It will always work if you are local because your router doesn't mind distributing packets behind the private LAN. Anything outside the network will not want to work because the client will try to send a packet to the server, but the server is behind a NAT(Network address translation) and since the router didn't see the server send out a packet first, the router will just discard the client's packet and never connect. However if the server sends out a udp packet to try to connect, the router likes to switch ports so you don't know which port the packet will come out of. That's what packet forwarding is for on the router. So when the client sends a packet, it goes to a different port than expected and the router still discards it. There are solutions such as "[url="http://www.brynosaurus.com/pub/net/p2pnat/"]hole punching[/url]". The easiest solution tho is to have a dedicated server outside of any NAT to handle the requests.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this