我有一台服务器在一台机器上运行,并且它使用的端口转发到我的路由器,另一台运行客户端的机器使用 ISP分配的外部IP地址而不是本地连接到服务器地址。这一切工作正常,它连接,但当我检查连接的套接字(客户端)的地址时,它显示的IP地址是完全不同的?它告诉我148.49.68.0
。我在ipconfig上找不到这个,也不明白这是从哪里出来的。客户端不应该显示我的外部地址吗? (看两台计算机使用相同的外部IP地址)。
[编辑] 添加了服务器来源
#include <iostream>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <string.h>
using namespace std;
int PORT;
const int winsock_version = 2;
const int max_con = 10;
string SERVER_ADDRS;
void Bind(SOCKET &serv,struct sockaddr_in &serv_info,int size);
void Listen(SOCKET &serv,int max_con);
void connection_info(struct sockaddr_in &client);
bool communication(SOCKET &client);
SOCKET Accept(SOCKET &serv);
int main(void){
WSADATA wsadata;
if ( WSAStartup(MAKEWORD(winsock_version,0),&wsadata) == 0 ){
cout<<"-[Initialized.]" << endl;
cout<<"-[Server Address (leave blank to scan for all IP's)]: ";
getline(cin,SERVER_ADDRS);
cout<<"-[Port]: ";
cin>>PORT;
struct sockaddr_in serv_info;
serv_info.sin_family = AF_INET;
serv_info.sin_port = htons(PORT);
if( sizeof(SERVER_ADDRS) > 5 ){
cout<<"-[Listening on: " << SERVER_ADDRS << "]" << endl;
serv_info.sin_addr.s_addr = inet_addr(SERVER_ADDRS.c_str());
}else{
cout<<"-[Scanning for All IP's]" << endl;
serv_info.sin_addr.s_addr = INADDR_ANY;
}
SOCKET serv;
serv = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if ( serv != INVALID_SOCKET ){
//------------------------------------------------------------
Bind(serv,serv_info,sizeof(serv_info));
Listen(serv,max_con);
struct sockaddr_in client_info;
int size = sizeof(client_info);
SOCKET client_sock = Accept(serv);
connection_info(client_info);
if (communication(client_sock) == true){
closesocket(serv);
closesocket(client_sock);
}
//------------------------------------------------------------
}
}else{
cout<<"-[Initialization failed, running cleanup.]" << endl;
}
if (WSACleanup() == 0){
cout<<"-[Cleanup Successful.]" << endl;
}
return 0;
}
void Bind(SOCKET &serv,struct sockaddr_in &serv_info,int size){
if ( bind(serv,(sockaddr*)&serv_info,size) != -1 ){
//Binding complete, now clear the port and allow for reuse if needed using setsockopt
char yes = '1';
if ( setsockopt(serv,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) != SOCKET_ERROR){
cout<<"-[Binding Successful.]" << endl;
}
}
}
void Listen(SOCKET &serv,int max_con){
if ( listen(serv,max_con) != -1 ){
cout<<"-[Listening for connections.] " << endl;
}
}
SOCKET Accept(SOCKET &serv){
struct sockaddr_in client_info;
int size = sizeof(client_info);
SOCKET recv;
recv = accept(serv,(sockaddr*)&client_info,&size);
if (recv != INVALID_SOCKET ) {
return recv;
}else{
cout<<"-[Invalid Socket.]" << endl;
}
}
void connection_info(struct sockaddr_in &client){
char *connected_ip= inet_ntoa(client.sin_addr);
int port = ntohs(client.sin_port);
cout<<"-[IP:" << connected_ip <<", Connected on PORT:"<< port << "]"<< endl;
}
bool communication(SOCKET &client){
cout<<"[---------------{CHAT}---------------]" << endl;
int bytes_in;
int bytes_out;
char recvd_text[80];
string send_text;
while(true){
cout<<"-[SERVER]: ";
getline(cin,send_text);
if (sizeof(send_text) > 0 ){
bytes_out = send(client,send_text.c_str(),send_text.length()+1,0);
cout<< endl;
if (bytes_out == SOCKET_ERROR){
cout<<"-[SERVER error in sending.]" << endl;
break;
}
}
bytes_in = recv(client,recvd_text,sizeof(recvd_text),0);
if (bytes_in > 0 ){
cout<<"-[CLIENT]: " << recvd_text << endl; //output on screen
}
if (bytes_in == 0){
cout<<"-[CLIENT has disconnected.]" << endl;
break;
}
if (bytes_in == SOCKET_ERROR){
cout<<"-[CLIENT closed unexpectedly.]" << endl;
break;
}
}
return true;
}
答案 0 :(得分:8)
试试这个:
#include <iostream>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <string>
int PORT;
const int winsock_version = 2;
const int max_con = 10;
std::string SERVER_ADDRS;
void Bind(SOCKET &serv, const struct sockaddr_in &serv_info);
void Listen(SOCKET &serv, int max_con);
void connection_info(struct sockaddr_in &client);
bool communication(SOCKET client);
SOCKET Accept(SOCKET serv, sockaddr_in &client_info);
int main(void)
{
WSADATA wsadata;
if ( WSAStartup(MAKEWORD(winsock_version,0),&wsadata) == 0 )
{
std::cout << "-[Initialized.]" << std::endl;
std::cout << "-[Server Address (leave blank to scan for all IP's)]: ";
std::getline(std::cin, SERVER_ADDRS);
std::cout << "-[Port]: ";
std::cin >> PORT;
struct sockaddr_in serv_info = {0};
serv_info.sin_family = AF_INET;
serv_info.sin_port = htons(PORT);
if( SERVER_ADDRS.length() > 0 )
{
std::cout << "-[Listening on: " << SERVER_ADDRS << "]" << std::endl;
serv_info.sin_addr.s_addr = inet_addr(SERVER_ADDRS.c_str());
}
else
{
std::cout << "-[Scanning for All IP's]" << std::endl;
serv_info.sin_addr.s_addr = INADDR_ANY;
}
SOCKET serv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( serv != INVALID_SOCKET )
{
//------------------------------------------------------------
Bind(serv, serv_info);
Listen(serv, max_con);
struct sockaddr_in client_info = {0};
SOCKET client_sock = Accept(serv, client_info);
if ( client_sock != INVALID_SOCKET )
{
connection_info(client_info);
communication(client_sock);
closesocket(client_sock);
}
//------------------------------------------------------------
closesocket(serv);
}
if (WSACleanup() == 0)
{
std::cout << "-[Cleanup Successful.]" << std::endl;
}
}
else
{
std::cout << "-[Initialization failed.]" << std::endl;
}
return 0;
}
void Bind(SOCKET serv, const struct sockaddr_in &serv_info)
{
//clear the port and allow for reuse before binding it
int yes = 1;
if ( setsockopt(serv, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes)) != SOCKET_ERROR)
{
std::cout << "-[Reuse Address Successful.]" << std::endl;
}
if ( bind(serv, (sockaddr*)&serv_info, sizeof(serv_info)) != -1 )
{
std::cout << "-[Binding Successful.]" << std::endl;
}
}
void Listen(SOCKET serv, int max_con)
{
if ( listen(serv, max_con) != -1 )
{
std::cout << "-[Listening for connections.] " << std::endl;
}
}
SOCKET Accept(SOCKET &serv, sockaddr_in &client_info)
{
int size = sizeof(client_info);
SOCKET recv = accept(serv, (sockaddr*)&client_info, &size);
if ( recv == INVALID_SOCKET )
{
std::cout << "-[Invalid Socket.]" << std::endl;
}
return recv;
}
void connection_info(struct sockaddr_in &client)
{
char *connected_ip = inet_ntoa(client.sin_addr);
int port = ntohs(client.sin_port);
st::cout << "-[IP:" << connected_ip << ", Connected on PORT:" << port << "]" << std::endl;
}
bool communication(SOCKET client)
{
std::cout << "[---------------{CHAT}---------------]" << std::endl;
int bytes_in;
int bytes_out;
char recvd_text[81];
std::string send_text;
while(true)
{
std::cout << "-[SERVER]: ";
std::getline(std::cin,send_text);
if (send_text.length() > 0 )
{
bytes_out = send(client, send_text.c_str(), send_text.length()+1, 0);
std::cout << std::endl;
if (bytes_out == SOCKET_ERROR)
{
std::cout << "-[SERVER error in sending.]" << std::endl;
break;
}
}
bytes_in = recv(client, recvd_text, sizeof(recvd_text)-1, 0);
if (bytes_in == SOCKET_ERROR)
{
std::cout << "-[CLIENT closed unexpectedly.]" << std::endl;
break;
}
else if (bytes_in == 0)
{
std::cout << "-[CLIENT has disconnected.]" << std::endl;
break;
}
else
{
recvd_text[bytes_in] = 0;
std::cout << "-[CLIENT]: " << recvd_text << std::endl; //output on screen
}
}
return true;
}
答案 1 :(得分:0)
WinSock getsockname()
和getpeername()
函数分别返回连接套接字的本地和远程IP。假设您已经在使用它们,那么请显示您的实际代码,因为您可能没有正确使用它们。
答案 2 :(得分:0)
获取外部IP的一种c / c ++方法是使用基于Web的IP地址API工具,将包含IP地址的网页下载到char数组中,并从HTML源中提取IP地址。这里有一些winsock代码来演示它。它使用http://api.ipify.org/的在线网络API。
//
// Winsock get external ip address from website api at api.ipify.org
// api.ipify.org
//
#include <string.h>
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cctype>
#include <locale>
#include <fstream>
#include <ctime>
#include <cstdlib>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
string website_HTML;
locale local;
char ipaddress[16];
int ic=0;
void get_Website(char *url );
char mystring[] = " ";
char seps[] = " ,\t\n";
char *token;
char lineBuffer[200][80] ={' '};
char buffer[10000];
char ip_address[16];
int i = 0, bufLen=0, j=0,lineCount=0;
int lineIndex=0, posIndex=0;
int main( void ){
SYSTEMTIME st;
GetLocalTime(&st);
char *today = new char[32];
memset(today,' ', sizeof(today) );
sprintf(today,"%d-%d-%d", st.wYear , st.wMonth , st.wDay);
memset(buffer,'\0',sizeof(buffer));
get_Website("api.ipify.org" );
for (size_t i=0; i<website_HTML.length(); ++i) website_HTML[i]= tolower(website_HTML[i],local);
token = strtok( buffer , seps );
while( token != NULL ){
strcpy(lineBuffer[lineIndex],token);
int dot=0;
for (int ii=0; ii< strlen( lineBuffer[lineIndex] ); ii++ ){
if (lineBuffer[lineIndex][ii] == '.') dot++;
if (dot>=3){
dot=0;
strcpy(ip_address,lineBuffer[lineIndex]);
}
}
token = strtok( NULL, seps );
lineIndex++;
}
cout<<"Your IP Address is "<< ip_address<<" \n\n";
return 0;
}
void get_Website(char *url ){
WSADATA wsaData;
SOCKET Socket;
SOCKADDR_IN SockAddr;
int lineCount=0;
int rowCount=0;
struct hostent *host;
char *get_http= new char[256];
memset(get_http,' ', sizeof(get_http) );
strcpy(get_http,"GET / HTTP/1.1\r\nHost: ");
strcat(get_http,url);
strcat(get_http,"\r\nConnection: close\r\n\r\n");
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0){
cout << "WSAStartup failed.\n";
system("pause");
//return 1;
}
Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
host = gethostbyname(url);
SockAddr.sin_port=htons(80);
SockAddr.sin_family=AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) != 0){
cout << "Could not connect";
system("pause");
//return 1;
}
send(Socket,get_http, strlen(get_http),0 );
int nDataLength;
while ((nDataLength = recv(Socket,buffer,10000,0)) > 0){
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r'){
website_HTML+=buffer[i];
i += 1;
}
}
closesocket(Socket);
WSACleanup();
delete[] get_http;
}
答案 3 :(得分:0)
(以下是Windows特定的。)
假设可以将AF_INET6
类型套接字配置为接受同一端口上的IPv4
和IPv6
连接:
int ipv6only = 0;
setsockopt(hSock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only));
我会在accept
函数之后立即实现客户端连接统计信息的检索:
char Sadr[max(sizeof(sockaddr_in), sizeof(sockaddr_in6))] = {0};
int ncbSzSadr = sizeof(Sadr);
if(getpeername(hSockAccept, (sockaddr*)Sadr, &ncbSzSadr) == 0)
{
if(ncbSzSadr == sizeof(sockaddr_in))
{
//IPv4
sockaddr_in* psadr_v4 = (sockaddr_in*)Sadr;
print("Connected to client from %s, port %u...\n",
inet_ntoa(psadr_v4->sin_addr),
(int)htons(psadr_v4->sin_port));
}
else if(ncbSzSadr == sizeof(sockaddr_in6))
{
//IPv6
sockaddr_in6* psadr_v6 = (sockaddr_in6*)Sadr;
WCHAR buff[256];
PCTSTR p_strIpv6 = InetNtop(AF_INET6, psadr_v6->sin6_addr, buff, _countof(buff));
_tprintf(L"Connected to client from %s, port %u...\n",
p_strIpv6,
(int)htons(psadr_v6->sin6_port));
}
else
{
_tprintf(L"ERROR: getpeername bad size=%d\n", ncbSzSadr);
}
}
else
{
_tprintf(L"ERROR: (%d) getpeername\n", WSAGetLastError());
}
请注意,报告的端口号将用于客户端的连接(而不是运行此代码的服务器端)。
顺便说一句,如果您想在连接的服务器端检索相同的信息,请使用完全相同的代码,但将getpeername
替换为getsockname
。