Sockets,Unix域UDP C ++ recvfrom无法填充源地址 [英] Sockets, Unix Domain UDP C++ recvfrom fail to populate the source address

查看:795
本文介绍了Sockets,Unix域UDP C ++ recvfrom无法填充源地址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在C ++中尝试使用UDP在Android上创建一个unix域套接字服务器和客户端。
我需要客户端向服务器发送一个消息(hi),从那里服务器需要向客户端发送数据。
我已经成功创建了双方的套接字,我能够从客户端接收服务器上的短消息。然而,recvfrom(..)在服务器上不填充结构sockaddr * src_addr,socklen_t * addrlen参数。使用这些src_addr和addrlen的后续sendto消息明显失败(sendto返回-1)。



下面是服务器的代码:

  int serverSocket = socket(PF_LOCAL,SOCK_DGRAM,0); 
int transmitBufferSize = OUTPUT_BUFFER_SIZE;
setsockopt(serverSocket,SOL_SOCKET,SO_SNDBUF,& sendingBufferSize,sizeof(sendingBufferSize));
struct sockaddr_un server;
memset(& server,0,sizeof server);
server.sun_family = AF_LOCAL;

// sun_path的第一个字节对于抽象命名空间应该是'\0'
const char * socket_name = SOCKET_NAME;
server.sun_path [0] ='\0';
strcpy(server.sun_path + 1,socket_name);
socklen_t sockaddr_len = sizeof(server.sun_family)+ strlen(socket_name)+ 1;
if(bind(serverSocket,(struct sockaddr *)& server,sockaddr_len)< 0){
close(serverSocket);
printf(无法绑定服务器socket\\\
);
return -1;
}

printf( - 套接字路径上的套接字绑定成功%s len%d\\\
,& server.sun_path [1],sockaddr_len);

_serverSocket = serverSocket;

稍后我从客户端收到一条消息:

  int opcode; 
_clientAddressLength = sizeof(struct sockaddr_un);
int numOfBytes = recvfrom(_serverSocket,_messageBuffer,INPUT_BUFFER,0,(struct sockaddr *)& _clientAddress,& _clientAddressLength);
if(numOfBytes!= 0)
{
printf(Get a message from client\\\
);
memcpy(& opcode,_messageBuffer,sizeof(opcode)); //我得到我期望的
}

但是_clientAddress是空的,_clientAddressLength设置为0。



后来

  int result = sendto _serverSocket 
,sendBuf
,sendBufSize
,0
,(const sockaddr *)& _clientAddress
,_clientAddressLength);

返回-1





最后感谢Nikolai N Fetissov的链接和一些挖掘我使它的工作。我想在UNIX DOMAIN抽象命名空间套接字上发布一个固定的,100%的双向UDP通信的工作示例。这是此 http的副本://www.toptip.ca/2013/01/unix-domain-socket-with-abstract-socket.html?m = 1 链接与一个固定的错误。



server.cpp



pre> #include< sys / socket.h>
#include< sys / un.h>
#include< stdio.h>
#include< string.h>

#include< unistd.h>`

#define SERVER_SOCKET#UdsServer//抽象命名空间的#替换为#

int main(void)
{
int socket_fd;
struct sockaddr_un server_address,client_address;
int bytes_received,bytes_sent,integer_buffer;
socklen_t address_length = sizeof(server_address.sun_family)+ strlen(SERVER_SOCKET);

if((socket_fd = socket(AF_UNIX,SOCK_DGRAM,0))< 0)
{
perror(server:socket);
return -1;
}

memset(& server_address,0,sizeof(server_address));
server_address.sun_family = AF_UNIX;
memcpy(server_address.sun_path,SERVER_SOCKET,sizeof(SERVER_SOCKET)-1); //路径不是C字符串,不是空转
server_address.sun_path [0] = 0;

if(bind(socket_fd,
(const struct sockaddr *)& server_address,
address_length)< 0)
{
perror server:bind);
close(socket_fd);
return -1;
}

for(;;)
{
bytes_received = recvfrom(socket_fd,
& integer_buffer,
sizeof(integer_buffer)
0,
(struct sockaddr *)& client_address,
& address_length);

if(bytes_received!= sizeof(integer_buffer))
{
printf(Error:recvfrom - %d.\\\
,bytes_received);
} else {
printf(received:%d.\\\
,integer_buffer);

integer_buffer + = 10;

bytes_sent = sendto(socket_fd,
& integer_buffer,
sizeof(integer_buffer),
0,
(struct sockaddr *)& client_address
address_length);
}
}

close(socket_fd);

return 0;
}

client.cpp

  #include< sys / socket.h> 
#include< sys / un.h>
#include< stdio.h>
#include< string.h>
#include< unistd.h>
#define SERVER_SOCKET#UdsServer
#define CLIENT_SOCKET#UdsClient
int main(void)
{
int socket_fd;
struct sockaddr_un server_address,client_address;
int bytes_received,bytes_sent,integer_buffer;
socklen_t address_length = sizeof(server_address.sun_family)+ strlen(CLIENT_SOCKET);`

if((socket_fd = socket(AF_UNIX,SOCK_DGRAM,0))< 0)
{
perror(client:socket);
return -1;
}

memset(& client_address,0,sizeof(client_address));
client_address.sun_family = AF_UNIX;
memcpy(client_address.sun_path,CLIENT_SOCKET,sizeof(CLIENT_SOCKET)-1);
client_address.sun_path [0] = 0;

if(bind(socket_fd,
(const struct sockaddr *)& client_address,
address_length)< 0)
{
perror client:bind);
return -1;
}

memset(& server_address,0,sizeof(server_address));
server_address.sun_family = AF_UNIX;
memcpy(server_address.sun_path,SERVER_SOCKET,sizeof(SERVER_SOCKET)-1);
server_address.sun_path [0] = 0;

integer_buffer = 1;

for(;;)
{
bytes_sent = sendto(socket_fd,
& integer_buffer,
sizeof(integer_buffer),
0 ,
(struct sockaddr *)& server_address,
address_length);

bytes_received = recvfrom(socket_fd,
& integer_buffer,
sizeof(integer_buffer),
0,
(struct sockaddr *)& server_address,
& address_length);

if(bytes_received!= sizeof(integer_buffer))
{
printf(Error:recvfrom - %d.\\\
,bytes_received);
return -1;
}

printf(received:%d\\\
,integer_buffer);

integer_buffer + = 1;

sleep(10);
}

close(socket_fd);

return 0;
}



我希望它有帮助,如果你看到更多的错误,请让我知道

解决方案

您正在将地址大小参数设置为Internet地址大小 sockaddr_in ,这对于Unix路径太小了。



编辑0:



我相信问题是不是 bind(2) - 客户端套接字,因此它没有名称,因此 recvfrom(2)



尝试此处(客户端需要与服务器名称不同的名称)。


I'm trying to create a unix domain socket server and client on Android in C++, using UDP. I need the client to send one message ("hi") to the server and from there on the server needs to send data to the client. I have successfully created the sockets on both sides, and I am able to receive a short message on the server from the client. However recvfrom(..) on the server does not populate the struct sockaddr *src_addr, socklen_t *addrlen arguments. And a subsequent sendto message using those src_addr and addrlen obviously fail (sendto returns -1).

Here's the code for the server :

int serverSocket = socket(PF_LOCAL, SOCK_DGRAM, 0);
int sendingBufferSize = OUTPUT_BUFFER_SIZE;
setsockopt(serverSocket, SOL_SOCKET, SO_SNDBUF, &sendingBufferSize, sizeof(sendingBufferSize));
struct sockaddr_un server;
memset(&server, 0, sizeof server);
server.sun_family = AF_LOCAL;

// the first byte of sun_path should be '\0' for abstract namespace
const char * socket_name = SOCKET_NAME;
server.sun_path[0] = '\0';
strcpy(server.sun_path + 1, socket_name);
socklen_t sockaddr_len = sizeof(server.sun_family) + strlen(socket_name) + 1;
if (bind(serverSocket, (struct sockaddr *) &server, sockaddr_len) < 0) {
    close(serverSocket);
    printf("Failed to bind the server socket\n");
    return -1;
}

printf("- Socket binding successful on socket path %s len %d\n", &server.sun_path[1], sockaddr_len);

_serverSocket = serverSocket;

And later I receive a message from the client:

int opcode;
_clientAddressLength = sizeof(struct sockaddr_un);
int numOfBytes = recvfrom(_serverSocket, _messageBuffer, INPUT_BUFFER, 0, (struct sockaddr *)&_clientAddress, &_clientAddressLength);
if (numOfBytes != 0)
{
    printf("Got a message from client\n");
    memcpy(&opcode, _messageBuffer, sizeof(opcode)); // I'm getting what I expected
}

However _clientAddress is empty and _clientAddressLength is set to 0.

And later

int result = sendto(_serverSocket
        , sendBuf
        , sendBufSize
        , 0
        , (const sockaddr*)&_clientAddress
        , _clientAddressLength);

returns -1

Thanks for your help guys!

EDIT:

Finally thanks to Nikolai N Fetissov's link and some digging I made it work. I'd like to post a fixed, 100% working example of bi-directional UDP communication over UNIX DOMAIN abstract namespace sockets. This is a copy of this http://www.toptip.ca/2013/01/unix-domain-socket-with-abstract-socket.html?m=1 link with a fixed bugs. For the future generations, as there aren't enough examples on this topic on the net.

server.cpp

#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h> 
#include <string.h>

#include <unistd.h>`

#define SERVER_SOCKET "#UdsServer" // The # is replaced by 0 for abstract namespace

int main(void)
{
int socket_fd;
struct sockaddr_un server_address, client_address; 
int bytes_received, bytes_sent, integer_buffer;
socklen_t address_length = sizeof(server_address.sun_family)+strlen(SERVER_SOCKET );

if ((socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
{
    perror("server: socket");
    return -1;
}

memset(&server_address, 0, sizeof(server_address));
server_address.sun_family = AF_UNIX;
memcpy(server_address.sun_path, SERVER_SOCKET,sizeof(SERVER_SOCKET)-1);// the path is not a C string, and is not NULL turminated
server_address.sun_path[0] = 0; 

if (bind(socket_fd,
         (const struct sockaddr *) &server_address,
         address_length) < 0)
{
    perror("server: bind");
    close(socket_fd);        
    return -1;
}

for (;;)
{
    bytes_received = recvfrom(socket_fd,
                              &integer_buffer,
                              sizeof(integer_buffer),
                              0, 
                              (struct sockaddr *) &client_address,
                              &address_length);

    if(bytes_received != sizeof(integer_buffer))
    {
        printf("Error: recvfrom - %d.\n", bytes_received);
    } else {
        printf("received: %d.\n", integer_buffer);

        integer_buffer += 10;

        bytes_sent = sendto(socket_fd,
                            &integer_buffer,
                            sizeof(integer_buffer),
                            0,
                            (struct sockaddr *) &client_address, 
                            address_length);
    }
}

close(socket_fd);

return 0;
}

client.cpp

#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define SERVER_SOCKET "#UdsServer" 
#define CLIENT_SOCKET "#UdsClient"
int main(void)
{
int socket_fd;
struct sockaddr_un server_address, client_address; 
int bytes_received, bytes_sent, integer_buffer;
socklen_t address_length = sizeof(server_address.sun_family) + strlen(CLIENT_SOCKET);`

if((socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
{
    perror("client: socket");
    return -1;
}

memset(&client_address, 0, sizeof(client_address));
client_address.sun_family = AF_UNIX;
memcpy(client_address.sun_path, CLIENT_SOCKET,sizeof(CLIENT_SOCKET )-1 );
client_address.sun_path[0] = 0;

if(bind(socket_fd,
        (const struct sockaddr *) &client_address, 
        address_length) < 0)
{
    perror("client: bind");
    return -1;
}

memset(&server_address, 0, sizeof(server_address));
server_address.sun_family = AF_UNIX;
memcpy(server_address.sun_path, SERVER_SOCKET,sizeof(SERVER_SOCKET)-1);
server_address.sun_path[0] = 0;

integer_buffer = 1;

for (;;)
{
   bytes_sent = sendto(socket_fd, 
                       &integer_buffer,
                       sizeof(integer_buffer),
                       0,
                       (struct sockaddr *) &server_address, 
                       address_length);

   bytes_received = recvfrom(socket_fd,
                             &integer_buffer,
                             sizeof(integer_buffer),
                             0, 
                             (struct sockaddr *) &server_address,
                             &address_length);

   if (bytes_received != sizeof(integer_buffer))
   {
       printf("Error: recvfrom - %d.\n", bytes_received);
       return -1;
   }

   printf("received: %d\n", integer_buffer);

   integer_buffer += 1;

   sleep(10);
}

close(socket_fd);

return 0;
}

I hope it helps, and if you see more bugs please let me know

解决方案

You are setting the address size argument to size of Internet address sockaddr_in, which is too small for Unix path.

Edit 0:

I believe the problem is that you are not bind(2)-ing the client socket, so it does not have a name, thus recvfrom(2) returns zero for address length.

Try code from here (the client needs a name different from the server name).

这篇关于Sockets,Unix域UDP C ++ recvfrom无法填充源地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆