C++ 确定服务器上已连接客户端的IP地址
我有一台运行在一台机器上的服务器,它使用的端口转发到我的路由器,另一台运行客户端的机器使用我的ISP分配的外部IP地址而不是本地地址连接到服务器。这一切都很好,它连接,但当我检查连接的套接字(客户端)的地址,它显示的IP地址是完全不同的?它显示的是C++ 确定服务器上已连接客户端的IP地址,c++,client-server,ip-address,winsock,ip,C++,Client Server,Ip Address,Winsock,Ip,我有一台运行在一台机器上的服务器,它使用的端口转发到我的路由器,另一台运行客户端的机器使用我的ISP分配的外部IP地址而不是本地地址连接到服务器。这一切都很好,它连接,但当我检查连接的套接字(客户端)的地址,它显示的IP地址是完全不同的?它显示的是148.49.68.0。我在ipconfig上找不到这个,也不明白它是从哪里冒出来的。客户不应该显示我的外部地址吗?(因为两台计算机使用相同的外部IP地址) [编辑]添加了服务器源 #include <iostream> #include
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;
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
国际港口;
const int winsock_version=2;
常数int max_con=10;
字符串服务器地址;
void绑定(SOCKET&serv,结构sockaddr\u in&serv\u info,int size);
无效侦听(套接字和服务,int max_con);
无效连接信息(客户端中的结构sockaddr);
bool通信(套接字和客户端);
套接字接受(套接字和服务);
内部主(空){
WSADATA WSADATA;
if(WSAStartup(MAKEWORD(winsock_版本,0),&wsadata)==0){
coutWinSockgetsockname()
和getpeername()
函数分别返回连接套接字的本地和远程IP。假设您已经在使用它们,请显示实际代码,因为您可能没有正确使用它们。尝试以下操作:
#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;
}
#包括
#包括
#包括
#包括
#包括
国际港口;
const int winsock_version=2;
常数int max_con=10;
std::字符串服务器地址;
无效绑定(SOCKET&serv,const struct sockaddr_in&serv_info);
无效侦听(套接字和服务,int max_con);
无效连接信息(客户端中的结构sockaddr);
bool通信(SOCKET客户端);
套接字接受(套接字服务、sockaddr\u in和客户端信息);
内部主(空)
{
WSADATA WSADATA;
if(WSAStartup(MAKEWORD(winsock_版本,0),&wsadata)==0)
{
标准::cout
获取外部ip的一种c/c++方法是使用基于web的ip地址API工具,将包含ip地址的网页下载到一个字符数组中,并从HTML源代码中提取ip地址。下面是一些winsock代码来演示。它使用的是的在线web 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;
}
//
//Winsock从api.ipify.org上的网站api获取外部ip地址
//api.ipify.org
//
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
#pragma注释(lib,“ws2_32.lib”)
字符串网页(HTML),;
当地语言环境;
字符地址[16];
int ic=0;
void get_网站(char*url);
char mystring[]=“”;
字符seps[]=“,\t\n”;
字符*令牌;
char lineBuffer[200][80]={''};
字符缓冲区[10000];
字符ip_地址[16];
int i=0,bufLen=0,j=0,lineCount=0;
int lineIndex=0,posIndex=0;
内部主(空){
系统时间st;
GetLocalTime&st;
char*today=新字符[32];
memset(今天),sizeof(今天);
sprintf(今天,“%d-%d-%d”,圣维耶尔,圣维蒙斯,圣维德日);
memset(缓冲区,'\0',sizeof(缓冲区));
获取大学网站(“api.ipify.org”);
对于(尺寸i=0;i=3){
点=0;
strcpy(ip_地址,lineBuffer[lineIndex]);
}
}
令牌=strtok(空,seps);
lineIndex++;
}
cout(以下是特定于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
148.49.68.0=>国防部网络信息中心,哥伦布俄亥俄州。您好,我没有使用getsockname或getpeername,我计算了服务器收到的sockaddr关于客户端的问题已经存在。我将编辑上面的帖子,请告诉我如何操作。是的,accept()确实返回有关已连接客户端的信息。但是,您的代码中有很多错误。与原始问题相关的最重要错误是accept()函数正在将客户端信息检索到一个sockaddr_in变量中,该变量仅对Accept()是本地的,但是您的connection_info()函数正在显示来自另一个sockaddr_in的值,该变量对main()是本地的,并且从未填充过任何数据,因此您正在显示随机垃圾。您的Accept()函数需要在检索到的数据中返回sockaddr_,而不是丢弃它。这不是他要求的。您正在做的是检索某人的公共IP
。此外,您是否确定ipify.org
服务将为您的方法提供服务?