本文介绍了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通信的工作示例。这是此链接与一个固定的错误。



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无法填充源地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-30 12:36