确定服务器上已连接客户端的IP地址

时间:2010-11-26 03:34:45

标签: c++ client-server ip-address winsock ip

我有一台服务器在一台机器上运行,并且它使用的端口转发到我的路由器,另一台运行客户端的机器使用 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;
}

4 个答案:

答案 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)

enter image description here

获取外部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类型套接字配置为接受同一端口上的IPv4IPv6连接:

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