2017-05-07 12 views
0

나는이 간단한 의사 소통이 작동하도록 고심하고있다.유닉스 소켓으로 PUB/SUB를 에뮬레이션하는 법 (AF_UNIX, SOCK_DGRAM)?

5 분 안에 zmq로 만들었습니다. 유닉스 소켓을 사용하는 것은 고통스런 일입니다. (분명히 자신감이 부족하기 때문입니다.)

는 서버입니다 :

#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는"쓰기 (렌)

EDIT2 : UNIX 클라이언트 socat : 클라이언트가 하나 socat 작동하지 않는/tmp를/스트림 -

그래서이 문제는 서버에있을 수 있다고 생각합니다.

답변

0

당신은 데이터 그램 소켓이 어떻게 작동하는지 오해하고 있습니다. 이것은 유닉스 소켓에 국한되지 않습니다. UDP에서도 똑같은 문제가 있습니다.

데이터 그램 소켓은 완전히 연결되어 있지 않습니다. 데이터 그램 소켓에있는 connect()은 실제로 아무런 연결도하지 않고 소켓에서 보낸 패킷의 기본 대상을 설정하기 만합니다. 편의를 위해 항상 같은 주소로 보낼 경우 sendto 대신 send을 사용할 수 있습니다.

클라이언트가 서버에 패킷을 처음으로 보내는 경우 서버가 특정 클라이언트에 응답하도록 만들 수 있습니다.이 경우 sendto을 사용하여 recvfrom에서 가져온 주소로 회신 할 수 있습니다. 그러나 클라이언트와 서버를 실제로 연결하려면 스트림 소켓 또는 seq 패킷 소켓을 대신 사용해야합니다. 이 경우 서버에서도 올바른 listen/accept 시퀀스를 수행하고 있는지 확인해야합니다.

사실 서버가 전송을 시도 할 때 오류를 인쇄하지 않으면 놀라실 것입니다. 그것은 write error: Transport endpoint is not connected입니다.

+0

예, 서버는 enpoint가 연결되어 있지 않다고 말합니다. 그러나 클라이언트를 시작하기 전에도 말합니다. 그래서 클라이언트가 연결되지 않아서라고 생각했습니다. 그래서, "블라인드 스트리밍"(제로 큐 PUB 또는 UDP 멀티 캐스트에서와 같이) 할 수있는 방법이 없으며, 유일한 방법은 연결을 수락하고 회신하는 것입니다. – d3k

+0

Unix 데이터 그램 소켓에는 브로드 캐스트/멀티 캐스트 기능이 없습니다. – Dolda2000

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

하지 쓰기이 세 번째 매개 변수 길이로 얻을 것으로 예상합니까;

+0

네, 맞습니다. 감사합니다. 그러나 코드는 수정 후에도 작동하지 않습니다. 그 위치의 "rc"는 잘라 내기 및 붙여 넣기 오류 (시간의 50 %)에서 왔습니다. – d3k