如何使用unix套接字模拟PUB / SUB(AF_UNIX,SOCK_DGRAM)?

时间:2017-05-07 17:50:55

标签: c sockets unix-socket

我正在努力使这种简单的沟通工作。

我在不到五分钟的时间内用zmq制作了它。 使用UNIX套接字这样做很痛苦(显然是因为我缺乏信心)。

这是服务器:

#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "streamsocket.h"

char *socket_path = "/tmp/stream";
int socket_fd=0;
struct sockaddr_un addr;

int main(){
        socket_setup();
        while(1){
                socket_sendstr("a");
                sleep(1);
        }
}

void socket_setup(){

  int rc;

  memset(&addr, 0, sizeof(addr));
  addr.sun_family = AF_UNIX;
  strcpy(addr.sun_path, socket_path);

  if ( (socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
    perror("socket error");
    exit(-1);
  }

  rc=bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr));
  if(rc<0){
    perror("bind error");
    exit(-2);
  }

}

int socket_sendstr(char* buffer) {
  int len=strlen(buffer);
  // corrected after suggestion in answer below (rc->len)
  // int rc=write(socket_fd, buffer, rc);
  int rc=write(socket_fd, buffer, len);

  if (rc != len) {
      if (rc > 0) fprintf(stderr,"partial write");
      else {
        perror("write error");
        //exit(-1);
      }
  }
}

这是客户:

#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(){
        char * server_filename = "/tmp/stream";
        char * client_filename = "/tmp/stream-client";

        struct sockaddr_un server_addr;
        struct sockaddr_un client_addr;

        int rc;

        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sun_family = AF_UNIX;
        strncpy(server_addr.sun_path, server_filename, 104); 

        memset(&client_addr, 0, sizeof(client_addr));
        client_addr.sun_family = AF_UNIX;
        strncpy(client_addr.sun_path, client_filename, 104);

        // get socket
        int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);

        // bind client to client_filename
        rc = bind(sockfd, (struct sockaddr *) &client_addr, sizeof(client_addr));
        if(rc==-1) perror("bind error");

        // connect client to server_filename
        rc = connect(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr));
        if(rc==-1) perror("connect error");


        char buf[1024];
        int bytes=0;
        while(bytes = read(sockfd, buf, sizeof(buf))){
                printf("%s\n",buf);
        }

        close(sockfd);
}

我做错了什么?

目前客户端没有打印任何内容。

EDIT1:正确错误的“rc”在服务器写入(,rc)中写入(,, len)

EDIT2:因为客户端也不工作socat:     socat UNIX-CLIENT:/ tmp / stream -

所以我认为问题可能出在服务器上。

2 个答案:

答案 0 :(得分:1)

int len=strlen(buffer);
  int rc=write(socket_fd, buffer, rc);

期望获得长度的第三个参数;

答案 1 :(得分:0)

你误解了数据报套接字是如何工作的,这不是Unix套接字本地的 - 你遇到了与UDP相同的问题。

数据报套接字完全没有连接。数据报套接字上的connect()实际上不进行任何连接,它只是为套接字上发送的数据包设置默认目标。这只是为了方便起见,因此您可以在始终发送到同一地址的情况下使用send代替sendto

如果客户端首先向服务器发送数据包,您可以让服务器回复特定客户端,在这种情况下,您可以使用sendto回复到recvfrom的相同地址}。但是,如果您确实想在客户端和服务器之间建立连接,则需要使用流套接字或seqpacket套接字。在这种情况下,您还需要确保在服务器中执行正确的listen / accept序列。

事实上,如果您的服务器在尝试发送时没有打印错误,我会感到惊讶。它应该是write error: Transport endpoint is not connected