2017-05-07 40 views
0

我正在努力使這個簡單的溝通工作。如何使用unix套接字(AF_UNIX,SOCK_DGRAM)模擬PUB/SUB?

我在不到五分鐘的時間裏用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的客戶:/ tmp目錄/流 -

所以我認爲這個問題可能在服務器上。

回答

0

您誤解了數據報套接字是如何工作的,而且這對Unix套接字來說並不是本地的 - 您也會遇到與UDP相同的問題。

數據報套接字完全沒有連接。數據報套接字上的一個connect()實際上並沒有進行任何連接,它只是爲在套接字上發送的數據包設置一個默認目標。這只是爲了方便起見,您可以在總是發送到相同地址的情況下使用send而不是sendto

如果客戶端首先向服務器發送數據包,則可以使服務器回覆特定客戶端,在這種情況下,您可以使用sendto回覆您從recvfrom獲得的相同地址。但是,如果您確實想在客戶端和服務器之間建立連接,則需要使用流套接字或seqpacket套接字。在這種情況下,您還需要確保在服務器中正確執行正確的listen/accept順序。

事實上,如果您的服務器在嘗試發送時沒有打印錯誤,我會(如果有的話)會感到驚訝。它應該是說write error: Transport endpoint is not connected

+0

是的,服務器說enpoint沒有連接,但是它在啓動任何客戶端之前也說過,所以我想這是因爲沒有連接任何客戶端。所以,沒有辦法做「盲流」(就像在zeromq PUB或UDP組播中一樣),唯一的辦法就是「接受和回覆」連接。 – d3k

+0

在Unix數據報套接字上沒有廣播/多播功能,如果這就是你要求的。 – Dolda2000

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

期望得到作爲第三個參數的長度;

+0

是的,你是對的,謝謝。但是,即使在更正之後代碼也不起作用....該位置中的「rc」來自剪切和粘貼錯誤(如50%的時間)。 – d3k

相關問題