如何在一个可执行文件中设置两个UDP套接字?

时间:2018-03-14 14:21:52

标签: c sockets

我是网络通信主题的新手,但是想建立一个UDP服务器客户端连接,一个参与者不断地广播数据是否有人正在收听,两个参与者开始接收和存储这些信息只要他们准备好这样做(如果他们错过了那之前发送的内容,那就没问题)。这个想法是除了一个参与者发送数据(发射和遗忘)和两个接收它们的参与者之外没有其他通信,没有任何形式的反馈给发送部分。现在我想让它在我的本地主机上运行,​​但是想在网络上使用它。

我一直在寻找一个解决方案已经有一段时间了,并且决定让客户端在两个独立的端口上连续广播文件流,这样接收的两个服务器可以分别绑定到一个端口而不会相互阻塞(如果有更好的方法,我愿意接受建议)。

到目前为止,我已经能够按照these指令与一个客户端和一个服务器建立这种通信。但是,当我尝试在客户端可执行文件中设置第二个套接字时,一旦到达sendto()部分,我总是会收到错误消息 无效参数

因为我自己找不到解决方案,但我想请求一些帮助。

到目前为止我的代码包含了 客户:

/** set up socket_1 properties */
struct addrinfo hints;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; // use my IP

/** Read address information of incoming connection */
int status;
struct addrinfo *servinfo;
if ((status = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
    return 1;
}   

/** loop through all the results and bind to the first we can */
int sockfd;
struct addrinfo *p; 
for ( p = servinfo; p != NULL; p = p->ai_next ) { 
    if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
        perror("listener: socket");
        continue;
    }

    //   /** Allow the reuse of a socket */
     //   if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
     //       printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
     //       exit(1);
     //   }

     //   /** Allow the reuse of a socket */
     //   if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
     //       printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
     //       exit(1);
     //   }


    break;
}
if (p == NULL) {
    printf("[ERROR]: Failed to bind broadcaster socket 1: %s.\n", strerror(errno) );
    return 2;
}


/** set up socket_2  */
// ( reuse socket_1 hints and change the port number )

/** Read address information of incoming connection */
int status_2;
struct addrinfo *servinfo_2;
if ((status_2 = getaddrinfo(NULL, MYPORT_2, &hints, &servinfo_2)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status_2));
    return 1;
}

/** loop through all the results and bind to the first we can */
int sockfd_2;
struct addrinfo *p_2;
for ( p_2 = servinfo_2; p_2 != NULL; p_2 = p_2->ai_next ) {
    if ((sockfd_2 = socket(p_2->ai_family, p_2->ai_socktype, p_2->ai_protocol)) == -1) {
        perror("listener: socket");
        continue;
    }

      //  /** Allow the reuse of a socket */
      //  if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
      //          printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
      //          exit(1);
      //  }

      //  /** Allow the reuse of a socket */
      //  if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
      //          printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
      //          exit(1);
      //  }

        break;
}

if (p_2 == NULL) {
    printf("[ERROR]: Failed to bind broadcaster socket 2: %s.\n", strerror(errno) );
    return 2;
}

...
some file read/write related stuff
...

while ( /* some condition */ )
{
    if ( ( readBytes = pread( fd, buf, BUFFER_SIZE, offset ) ) == -1 ){
        printf("[ERROR]: %s.\n", strerror(errno) );
        free( buf );
        close( fd );
        close( sockfd );
        exit(1);
    }


// the next line is generating the error message 
    if ( ( numbytes = sendto( sockfd, buf, readBytes, 0, p->ai_addr, p->ai_addrlen ) ) == -1 )
    {
        perror("sender_1: sendo.\n");
        free( buf );
        close( fd );
        close( sockfd );
        exit(1);
    }

    if ( ( numbytes = sendto( sockfd_2, buf, readBytes, 0, p_2->ai_addr, p_2->ai_addrlen ) ) == -1 )
    {   
            perror("sender_2: sendo.\n");
            free( buf );
            close( fd );
            close( sockfd_2 );
            exit(1);
    }   


}

.
.
.

free( buf );
freeaddrinfo(servinfo);
freeaddrinfo(servinfo_2);

printf( "Broadcasting complete.\n" );

/** Clean what is not necessary anymore */
close( fd );
close( sockfd );

return 0;
}

我尝试添加重用端口和IP功能,以确保没有任何阻止新套接字的设置,但这并没有解决我的问题

我的服务器端似乎工作正常,但以防万一我也会在这里发布:

int main(int argc, char **argv)
{
if (argc < 2){
    printf("Please provide image Name ID.\n");
    exit(1);
}

struct addrinfo hints;
struct addrinfo *servinfo = NULL; // will point to getaddrinfo() results

memset(&hints, 0, sizeof hints); // make sure struct is empty 
hints.ai_family = AF_UNSPEC; // don't care if IPv4 or IPv6
hints.ai_socktype = SOCK_DGRAM;     // Use UDP protocol
hints.ai_flags = AI_PASSIVE;

int res;
if ((res = getaddrinfo( NULL, argv[1]/* SERVERPORT*/, &hints, &servinfo )) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(res));
    return 1;
}

/** Get socket file descriptor  */
int sockfd;
struct addrinfo *p = NULL;
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype,
        p->ai_protocol)) == -1) {
        perror("talker: socket");
        continue;
    }

    /** Allow the reuse of an IP */
    if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
            printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );  
            exit(1);
    }       

    /** Allow the reuse of a socket */
    if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
            printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );  
            exit(1);
    }       


        /** Bind found socket to desired port */
    if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        printf("[ERROR]: Failed to bind socket to desired port: %s.\n", strerror( errno ) );
        continue;
    }
break;
}

struct timeval read_timeout;
read_timeout.tv_sec = 30;
read_timeout.tv_usec = 500;
if ( setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof read_timeout) < 0 ){
    printf( "[ERROR]: %s.\n", strerror(errno) );
}

...
some file read/write stuff
...

while ( ( numbytes = recvfrom(sockfd, buf, BUFFER_SIZE, 0, (struct sockaddr *)&their_addr, &addr_len ) ) != -1) 
{
.
.
.
}
printf("Done broadcasting.\n");

freeaddrinfo(servinfo);

close(sockfd);

return 0;
}

如果有人能给我一些帮助或者指出正确的方向寻找解决方案,我将不胜感激。

祝你好运

0 个答案:

没有答案