php socket 获取客户端ip地址

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php socket 获取客户端ip地址相关的知识,希望对你有一定的参考价值。

服务器接收到客户端的连接后, 怎么通过生成的socket获取客户端的ip地址呢? 我用socket_getpeerbyname()获取到的ip是服务器的ip, 我需要客户端的ip

socket_getpeername() 获取远程类似主机的ip地址
socket_getsockname() 获取本地socket的ip地址
怎么感觉你用的实际上是对的,难道用nginx一类的负载均衡服务器了追问

socket_getpeername()获取到的ip应该是客户端的ip对吗? 我不知道为什么获取到的ip是服务器的ip. 我是用iis服务器, 然后把内网映射出去让外网访问调试的

参考技术A 不是有一个超全局数组$_SERVER吗? 这个数组可以获取吧追问

怎么获?

linux C++ socket 如何获取客户端ip地址?(第一次accept无法获取客户端ip原因,第一次获取ip为0.0.0.0,需要赋初始size)

参考文章1:C++根据SOCKET获取套接字IP、Port等信息的代码

参考文章2:获取socket客户端的IP

参考文章3:第一次accept 无法获取客户端 ip

第一次获取的客户端的ip老是0.0.0.0,不知道是怎么回事,后面连接进来的客户端ip就是正确的

原因是没有给下面代码中的client_len参数赋初始size

 if ( (m_clientfd=accept(m_listenfd, (struct sockaddr*)&client_address, &client_len)) <= 0)

The addrlen argument is a value-result argument: the caller must initialize it to contain the size (in bytes) of the structure pointed to by addr; on return it will contain the actual size of the peer address.
addrlen 参数是一个值结果参数:调用者必须将其初始化为包含 addr 指向的结构的大小(以字节为单位); 返回时它将包含对等地址的实际大小。
注:这个参数既是输入,也是输出,但第一次没有输出,所以我们需要给它赋值,,,虽然如果不赋值,除第一次外也行。。。

附socket服务端代码

socket_server_4_docker_test.cpp

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <stdlib.h>

#include <mutex>
#include <sys/time.h>

#define KY_AI_API_MAX_BUF_LEN 1024
struct sockaddr_in client_address;	  //arnold add 20220530
unsigned int client_len;	  //arnold add 20220530
char client_ip[256];
static  std::mutex s_ky_ai_mutex;


#define KY_AI_RECV_DATA_FILE "./test_log/ky_ai_recv_data_"


#if 1
#define KY_AI_RECV_DATA(format, ...)                                                \\
    do    /*1.check file size*/                                                    \\
           s_ky_ai_mutex.lock();                                                    \\
          /*2.generate a time string and connect it to the log string tail.*/       \\
          char str[KY_AI_API_MAX_BUF_LEN] = 0;                                    \\
	      if(format[0] != '\\n' && strlen(format) > 1)                           \\
                                                                                   \\
              struct timeval tv;                                                    \\
              struct tm* t;                                                         \\
              gettimeofday(&tv, NULL);                                              \\
              t = localtime(&tv.tv_sec);                                            \\
              sprintf(str,"[%04d-%02d-%02d %02d:%02d:%02d.%03ld] ",                 \\
                             1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday,          \\
                             t->tm_hour, t->tm_min, t->tm_sec, tv.tv_usec / 1000);  \\
              strcat(str,format);                                                   \\
                                                                                   \\
           else                                                                     \\
                                                                                   \\
              strcpy(str,format);                                                   \\
	                                                                	    \\
          /*3. write the log to the cfg file*/                                      \\
	  std::string local_ip(client_ip);					    \\
          std::string filename = KY_AI_RECV_DATA_FILE + local_ip + ".txt";          \\
          FILE* logFile = fopen(filename.c_str(), "a");                             \\
          fprintf(logFile, str, ##__VA_ARGS__);                                     \\
          fclose(logFile);                                                          \\
          s_ky_ai_mutex.unlock();                                                   \\
        while (0)
#endif










class CTcpServer

public:
  int m_listenfd;   // 服务端用于监听的socket
  int m_clientfd;   // 客户端连上来的socket
 
  CTcpServer();
 
  bool InitServer(int port);  // 初始化服务端
 
  bool Accept();  // 等待客户端的连接
 
  // 向对端发送报文
  int  Send(const void *buf,const int buflen);
  // 接收对端的报文
  int  Recv(void *buf,const int buflen);
 
  void CloseClient();    // 关闭客户端的socket
  void CloseListen();    // 关闭用于监听的socket
 
 ~CTcpServer();
;
 
CTcpServer TcpServer;
 

static void demo_signal_call_back(int sig)	//arnold modified 20220420
 
  printf("\\n");
  printf("received signal: [%d]\\n\\n", sig);

  exit(0);



int main()

  signal(SIGCHLD,SIG_IGN);  // 忽略子进程退出的信号,避免产生僵尸进程

  //signal acquisition[must must must add]	//信号(可在摄像头里用kill -l查看信号表)
  signal(SIGINT, demo_signal_call_back);//interrupt	//ctrl+c	//kill -2
  signal(SIGTERM, demo_signal_call_back);//abort	//kill或kill all命令	//kill -15	
  signal(SIGFPE, demo_signal_call_back);//math processing	//浮点异常	//kill -8
  signal(SIGKILL, demo_signal_call_back);//memory crossover	//kill -9
  signal(SIGSEGV,demo_signal_call_back);	//无效的内存引用
  signal(SIGPIPE,SIG_IGN);	//管道破裂:比如没有读端口的管道
 
  //if (TcpServer.InitServer(5051)==false)
	if (TcpServer.InitServer(6969)==false)
   printf("服务端初始化失败,程序退出。\\n"); return -1; else printf("服务端初始化成功。\\n");
 
  while (1)
  
    if (TcpServer.Accept() == false) continue;
 
    if (fork()>0)  TcpServer.CloseClient(); continue;   // 父进程回到while,继续Accept。


 
    //signal(SIGINT,SIG_IGN);  //测试给子进程屏蔽ctrl+c会怎么样,父进程死后,孤儿进程还会在吗? //还在的,而且子进程用ctrl+c杀不死了




    // 子进程负责与客户端进行通信,直到客户端断开连接。
    TcpServer.CloseListen();
 
    printf("客户端已连接。\\n");
 
    // 与客户端通信,接收客户端发过来的报文后,回复ok。
    char strbuffer[1024];
 
    while (1)
    
      memset(strbuffer,0,sizeof(strbuffer));
      if (TcpServer.Recv(strbuffer,sizeof(strbuffer))<=0) break;
	printf("#################### receive start ####################\\n");
     

	//memset(client_ip, 0, sizeof(client_ip));
	//sprintf(client_ip, "%u.%u.%u.%u", NIPQUAD(client_address.sin_addr.s_addr));

	printf("接收:%s\\n",strbuffer);
      //printf("接收:[%s] %s\\n",inet_ntoa(client_address.sin_addr), strbuffer);
	KY_AI_RECV_DATA("%s\\n\\n", strbuffer);













	printf("#################### receive end ####################\\n\\n");
#if 0
      strcpy(strbuffer,"ok");
      if (TcpServer.Send(strbuffer,strlen(strbuffer))<=0) break;
      printf("发送:%s\\n",strbuffer);
#endif
    
 
    printf("客户端已断开连接。\\n");
 
    return 0;  // 或者exit(0),子进程退出。
  

 
CTcpServer::CTcpServer()	//在对象创建的时候会自动调用?

  // 构造函数初始化socket
  m_listenfd=m_clientfd=0;

 
CTcpServer::~CTcpServer()	//析构函数:在对象销毁的时候自动调用?

  if (m_listenfd!=0) 
  
    close(m_listenfd);  // 关闭m_listenfd
    printf("m_listenfd has been closed!\\n\\n");
    
  if (m_clientfd!=0)
  
    close(m_clientfd);  // 关闭m_clientfd
    printf("m_clientfd has been closed!\\n\\n");
    


 
// 初始化服务端的socket,port为通信端口
bool CTcpServer::InitServer(int port)

  if (m_listenfd!=0)  close(m_listenfd); m_listenfd=0; 
 
  m_listenfd = socket(AF_INET,SOCK_STREAM,0);  // 创建服务端的socket
 
  // 把服务端用于通信的地址和端口绑定到socket上
  struct sockaddr_in servaddr;    // 服务端地址信息的数据结构
  memset(&servaddr,0,sizeof(servaddr));
  servaddr.sin_family = AF_INET;  // 协议族,在socket编程中只能是AF_INET
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  // 本主机的任意ip地址
  servaddr.sin_port = htons(port);  // 绑定通信端口
  if (bind(m_listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) != 0 )
   close(m_listenfd); m_listenfd=0; printf("bind error\\n"); return false; 
 
  // 把socket设置为监听模式
  if (listen(m_listenfd,5) != 0 )  close(m_listenfd); m_listenfd=0; return false; 
 
  return true;

 
bool CTcpServer::Accept()

  //if ( (m_clientfd=accept(m_listenfd,0,0)) <= 0) return false;




	memset(&client_address,0,sizeof(client_address));
	client_len = sizeof(client_address);
  if ( (m_clientfd=accept(m_listenfd, (struct sockaddr*)&client_address, &client_len)) <= 0)
	
		printf("accept failed!\\n");
		return false;
	 		




	//printf("IP:[%s]\\n",inet_ntoa(client_address.sin_addr));
	memcpy(client_ip, inet_ntoa(client_address.sin_addr), strlen(inet_ntoa(client_address.sin_addr)));
	printf("IP:[%s]\\n",client_ip);



 
  	return true;

 
int CTcpServer::Send(const void *buf,const int buflen)

  return send(m_clientfd,buf,buflen,0);

 
int CTcpServer::Recv(void *buf,const int buflen)

  return recv(m_clientfd,buf,buflen,0);

 
void CTcpServer::CloseClient()    // 关闭客户端的socket

  if (m_clientfd!=0)  close(m_clientfd); m_clientfd=0; 

 
void CTcpServer::CloseListen()    // 关闭用于监听的socket

  if (m_listenfd!=0)  close(m_listenfd); m_listenfd=0; 


以上是关于php socket 获取客户端ip地址的主要内容,如果未能解决你的问题,请参考以下文章

为啥获取客户端ip地址总是:204.204.204.204

Socket 如何知道断开连接的客户端ip地址

怎么用Socket.RemoteEndPoint 获取客户端IP和端口 ?

linux C++ socket 如何获取客户端ip地址?(第一次accept无法获取客户端ip原因,第一次获取ip为0.0.0.0,需要赋初始size)

如何通过Socket获得所有客户端连接的IP地址

如何获得Socket连接客户端的IP地址