Sockets C++;-如何从struct sockaddr获取IP和端口
我正试图用libmilter开发一个邮件混合器。因此,我必须定义一些回调函数。目前我正在努力使用connect()函数。声明如下:Sockets C++;-如何从struct sockaddr获取IP和端口,sockets,c++11,Sockets,C++11,我正试图用libmilter开发一个邮件混合器。因此,我必须定义一些回调函数。目前我正在努力使用connect()函数。声明如下: sfsistat mlfi_connect(SMFICTX *ctx, char *hostname, struct sockaddr *hostaddr); 当客户机连接到milter时,调用此回调。现在我想记录主机名、IP和端口。对于主机名,这很简单。但我无法让它与主机地址一起工作 我在StackOverflow上找到了一些类似的文章,但没有一篇适合我。看起来
sfsistat mlfi_connect(SMFICTX *ctx, char *hostname, struct sockaddr *hostaddr);
当客户机连接到milter时,调用此回调。现在我想记录主机名、IP和端口。对于主机名,这很简单。但我无法让它与主机地址一起工作
我在StackOverflow上找到了一些类似的文章,但没有一篇适合我。看起来我必须将结构转换为sockaddr_in或sockaddr_in 6,但我遇到了诸如“成员访问到不完整类型'struct sockaddr_in'”之类的编译器问题
这就是我所尝试的:
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
string ipandport;
switch (hostaddr->sa_family) {
case AF_INET:
sin = (struct sockaddr_in *) hostaddr;
unsigned char *ip = (unsigned char *)&sin->sin_addr.s_addr;
break;
case AF_INET6:
// TODO
break;
default:
ipandport = "unknown";
}
我从未想过要获得如此琐碎的信息会如此困难:-)IPv4的非编译测试示例。IPv6几乎是一样的,只需调整使用的常量定义(阅读inet\u ntop手册页)
#包括
无效打印(结构sockaddr*s)
{
结构sockaddr_in*sin=(结构sockaddr_in*)s;
字符ip[INET_ADDRSTRLEN];
uint16_t端口;
inet\u pton(AF\u inet,sin->sin\u addr,ip,sizeof(ip));
端口=htons(sin->sin\u端口);
printf(“主机%s:%d\n”,ip,端口);
}
我找到了不同的答案。在这里发布后,我再次在谷歌上搜索并找到了这个,它最终对我有用:
sfsistat mlfi_connect(SMFICTX *ctx, char *hostname, struct sockaddr *hostaddr) {
assert(ctx != NULL);
assert(hostaddr != NULL);
string ipandport;
char clienthost[NI_MAXHOST];
char clientport[NI_MAXSERV];
int result = getnameinfo(hostaddr, sizeof(*hostaddr),
clienthost, sizeof(clienthost),
clientport, sizeof (clientport),
NI_NUMERICHOST | NI_NUMERICSERV);
if(result != 0)
ipandport = "unknown";
else
{
if (hostaddr->sa_family == AF_INET)
ipandport = string(clienthost) + ":" + string(clientport);
else
ipandport = "[" + string(clienthost) + "]:" + string(clientport);
}
if (hostname == nullptr)
hostname = const_cast<char *>("unknown");
Client *con = new Client(string(hostname), ipandport);
// Store new client data
smfi_setpriv(ctx, static_cast<void *>(con));
cout << "id=" << con->getId()
<< " connect from " << con->getHostname()
<< " IP and port " << con->getIPandPort() << endl;
return SMFIS_CONTINUE;
}
sfsistat mlfi_connect(SMFICTX*ctx,char*hostname,struct sockaddr*hostaddr){
断言(ctx!=NULL);
断言(hostaddr!=NULL);
字符串ipandport;
char clienthost[NI_MAXHOST];
char clientport[NI_MAXSERV];
int result=getnameinfo(hostaddr,sizeof(*hostaddr),
clienthost,sizeof(clienthost),
clientport,sizeof(clientport),
NI_NUMERICHOST | NI_NUMERICSERV);
如果(结果!=0)
ipandport=“未知”;
其他的
{
如果(hostaddr->sa_family==AF_INET)
ipandport=string(clienthost)+“:”+string(clientport);
其他的
ipandport=“[”+字符串(clienthost)+“]:”+字符串(clientport);
}
如果(主机名==nullptr)
主机名=const_cast(“未知”);
Client*con=新客户端(字符串(主机名)、ipandport);
//存储新的客户端数据
smfi_setpriv(ctx、静态_cast(con));
coutinet\u ntop
需要从二进制转换为字符串,而不是inet\u pton
$ man inet_ntop
...
This function converts the network address structure src in the af address family into a character string. The
resulting string is copied to the buffer pointed to by dst, which must be a non-null pointer. The caller specifies
the number of bytes available in this buffer in the argument size.
例如:
#include <arpa/inet.h>
...
char address[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &my_sockaddr_in.sin_addr, address, sizeof(address));
#包括
...
字符地址[INET_ADDRSTRLEN];
inet_ntop(AF_inet,&my_sockaddr_in.sin_addr,address,sizeof(address));
谢谢。当我在等待答案时,我找到了一个不同的解决方案。它不应该是ntohs
而不是htons
?ntohs()和htons()执行完全相同的操作。要么不执行任何操作,要么交换上下字节。大多数套接字实现都使用宏来将一个替换为另一个。奇怪的是,我的inet\u pton
原型(如手册5.022019-03-06中所列)不包括您用于sizeof
的第四个参数。这是错误的方法。inet\u pton
将中的字符串转换为struct sockaddr\u,需要inet\u ntop
将中的struct sockaddr\u转换为字符串。(请参阅我的答案。)
#include <arpa/inet.h>
...
char address[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &my_sockaddr_in.sin_addr, address, sizeof(address));
struct sockaddr_in client, server;
SOCKET s , new_socket;
s = socket(AF_INET , SOCK_STREAM , 0 )
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
bind(s ,(struct sockaddr *)&server , sizeof(server))
//pending connection in queue is 1
listen(s , 1);
new_socket = accept(s , (struct sockaddr *)&client, &c);
printf ("client remote port: %i\n", ntohs(client.sin_port) );