linux C++ socket 如何获取客户端ip地址?(第一次accept无法获取客户端ip原因,第一次获取ip为0.0.0.0,需要赋初始size)
Posted Dontla
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux C++ socket 如何获取客户端ip地址?(第一次accept无法获取客户端ip原因,第一次获取ip为0.0.0.0,需要赋初始size)相关的知识,希望对你有一定的参考价值。
参考文章1:C++根据SOCKET获取套接字IP、Port等信息的代码
第一次获取的客户端的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;
以上是关于linux C++ socket 如何获取客户端ip地址?(第一次accept无法获取客户端ip原因,第一次获取ip为0.0.0.0,需要赋初始size)的主要内容,如果未能解决你的问题,请参考以下文章
手把手写C++服务器(38):面试必背!Linux网络socket编程必会十问!
事件上的 C++ 侦听器未使用套接字 io C++ 客户端获取事件