客户端如果访问的是局域网的IP地址,程序执行均正常,但是如果访问的是外网IP,即使路由器部分已经做好了的端口映射,均无法访问到正确的主机,查代码发现是在gethostbyaddr这里出错了,导致在还没连接到指定端口的主机那段代码之前就出错了,代码如下:int TcpConnect(char *strHost, int nPort, SOCKET *soOut, int nSendBufSize, int nRcvBufSize)
{
if(soOut == NULL || strHost == NULL)//保证是引用传入
{
AfxMessageBox("TcpConnect() 非引用传入参数!");

return RET_UNSUCCESS;
}
int ret;
SOCKET so_fd;
struct sockaddr_in l_addr_in;//
struct in_addr l_addrhost;
LPHOSTENT targethost;
CString strTemp;
//解析地址
memset(&l_addrhost, 0x00, sizeof(l_addrhost));//清0
l_addrhost.s_addr = inet_addr(strHost);

if (l_addrhost.s_addr == INADDR_NONE)
{
targethost = gethostbyname(strHost);
} else
{
//strHost如果是局域网机器的IP地址那执行到下面这句均是正确的,但如果是外网的IP地址,因为外网那台机器是连接
//在路由器上的,所以strHost其实指向的是路由器的地址,再执行到下句时targethost返回的是0,不知道该怎么弄了
//由于还没执行到下面的connect,所以跟路由器端口映射也没关系,并且外网那台的端口映射已经测试过是完全好用的。
targethost = gethostbyaddr((const char *)&l_addrhost,sizeof(l_addrhost), AF_INET);
} if(targethost == NULL)
{
long nRetCode=WSAGetLastError();
strTemp.Format("TcpConnect() 无法解释的服务器主机名:%s! [WSA错误代码:%d]",strHost,nRetCode);
AfxMessageBox(strTemp);
return RET_UNSUCCESS;
}

//创建客户端TCP连接套接字
so_fd = socket(AF_INET, SOCK_STREAM, 0);
if( so_fd == INVALID_SOCKET )
{
long nRetCode=WSAGetLastError();
strTemp.Format("TcpConnect() 创建客户端TCP连接套接字失败! [WSA错误代码:%d]",nRetCode);
AfxMessageBox(strTemp);

return RET_UNSUCCESS;
}

//设置消息
if(gSocketTable.hWnd != 0)
{
ret = WSAAsyncSelect(so_fd, gSocketTable.hWnd, gSocketTable.msgID, FD_ACCEPT|FD_CLOSE|FD_READ);
if(ret == SOCKET_ERROR)
{
long nRetCode=WSAGetLastError();
strTemp.Format("TcpConnect() 套接字:%d设置异步事件失败! [WSA错误代码:%d]",so_fd,nRetCode);
SocketClose(FALSE,so_fd);
AfxMessageBox(strTemp);
return RET_UNSUCCESS;
}
}
u_long l_arg = 1L;//非阻模式,0则为阻塞模式
ret = ioctlsocket(so_fd, FIONBIO, &l_arg);//非阻塞设置5.1.12 ioctlsocket()
if(ret == SOCKET_ERROR)
{
long nRetCode=WSAGetLastError();
strTemp.Format("TcpConnect() 套接字:%d非阻塞设置失败! [WSA错误代码:%d]",so_fd,nRetCode);
SocketClose(FALSE,so_fd);
AfxMessageBox(strTemp);
return RET_UNSUCCESS;
}//连接服务器
l_addr_in.sin_family = AF_INET;
l_addr_in.sin_port   = htons(nPort);
l_addr_in.sin_addr   = *((LPIN_ADDR)*targethost->h_addr_list);
ret = connect(so_fd, (LPSOCKADDR)&l_addr_in,sizeof(l_addr_in));
long l_err=0;
if(ret == SOCKET_ERROR)
{
int l_err = WSAGetLastError();
if(l_err != WSAEWOULDBLOCK)//非阻塞错误<Windows下Socket编程>5.1.4 connect()
{
strTemp.Format("TcpConnect() 套接字:%d连接远端主机失败! [WSA错误代码:%d]",so_fd,l_err);
SocketClose(FALSE,so_fd);
AfxMessageBox(strTemp);
return RET_UNSUCCESS;
}
else if(l_err == WSAECONNREFUSED){
strTemp.Format("TcpConnect() 套接字:%d连接远端主机被拒绝! [WSA错误代码:%d]",so_fd,l_err);
SocketClose(FALSE,so_fd);
AfxMessageBox(strTemp);
return RET_CONNECT_REFUSED;
}
fd_set s_set;//fd_set结构来表示一组等待检查的套接口
struct timeval *sel;
struct timeval tmp_sel;
FD_ZERO(&s_set);

FD_SET(so_fd, &s_set);//向集合添加描述字s_set
tmp_sel.tv_sec = 10;//等待10秒  见MSDN tv_sec:以秒为单位tv_usec:以毫秒单位
tmp_sel.tv_usec = 0;
sel = &tmp_sel;
ret = (int)select(0, NULL, &s_set, NULL, sel);
if(ret==0)
{
strTemp.Format("TcpConnect() 套接字:%d SelectOne()操作超时失败!",so_fd);
SocketClose(FALSE,so_fd);
AfxMessageBox(strTemp);
return RET_UNSUCCESS; }
else if(ret < 0)
{
long nRetCode=WSAGetLastError();
strTemp.Format("TcpConnect() 套接字:%dSelectOne()操作失败! [WSA错误代码:%d]",so_fd,nRetCode);

SocketClose(FALSE,so_fd);
AfxMessageBox(strTemp);
return RET_UNSUCCESS;
}

}