Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets C++;-如何从struct sockaddr获取IP和端口_Sockets_C++11 - Fatal编程技术网

Sockets C++;-如何从struct sockaddr获取IP和端口

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上找到了一些类似的文章,但没有一篇适合我。看起来

我正试图用libmilter开发一个邮件混合器。因此,我必须定义一些回调函数。目前我正在努力使用connect()函数。声明如下:

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));

cout
inet\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) );