首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UNIX域套接字编程3个套接字

UNIX域套接字编程3个套接字
EN

Stack Overflow用户
提问于 2015-05-09 18:02:55
回答 2查看 1.6K关注 0票数 2

我正在尝试创建一个server.c文件,该文件支持3个套接字,这些套接字由3个客户端类表示: client1、client2、client3。

在我的server.c文件中,我目前在互联网上找到了这个代码。

如果我想让它有3个插座。我想使用select()命令查看3个客户端的写活动。我的问题是如何使用它来支持3个套接字。

我可以将这3个客户端绑定到服务器可以监听的3个套接字上吗?如果是这样,服务器如何分别侦听这3个套接字?有可能是数组?

代码语言:javascript
复制
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>

#define socket1 "sock1"
#define socket2 "sock2"
#define socket3 "sock3"

int main(int argc, char *argv[]) {
    //struct sockaddr_un addr;
    struct sockaddr_un addr1;
    struct sockaddr_un addr2;
    struct sockaddr_un addr3;
    char buf[100];
    int socket1;
    int socket2;
    int socket3;
    //int fd;
    int cl,rc;

    if (argc > 1) socket_path=argv[1];

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

    memset(&addr1, 0, sizeof(addr1));
    addr1.sun_family = AF_UNIX;
    strncpy(addr1.sun_path, socket_path, sizeof(addr1.sun_path)-1);

    unlink(socket_path1);

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

    memset(&addr2, 0, sizeof(addr2));
    addr1.sun_family = AF_UNIX;
    strncpy(addr2.sun_path, socket_path, sizeof(addr2.sun_path)-1);

    unlink(socket_path2);

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

    memset(&addr3, 0, sizeof(addr3));
    addr3.sun_family = AF_UNIX;
    strncpy(addr3.sun_path, socket_path, sizeof(addr3.sun_path)-1);

    unlink(socket_path3);

    if (bind(socket1, (struct sockaddr*)&addr1, sizeof(addr1)) == -1) {
        perror("bind error");
        exit(-1);
    }

    if (bind(socket2, (struct sockaddr*)&addr2, sizeof(addr2)) == -1) {
        perror("bind error");
        exit(-1);
    }

    if (bind(socket3, (struct sockaddr*)&addr3, sizeof(addr3)) == -1) {
        perror("bind error");
        exit(-1);
    }

    if (listen(socket1, 5) == -1) {
        perror("listen error");
        exit(-1);
    }

    if (listen(socket2, 5) == -1) {
        perror("listen error");
        exit(-1);
    }

    if (listen(socket3, 5) == -1) {
        perror("listen error");
        exit(-1);
    }

    while (1) {
        if ( (cl = accept(fd, NULL, NULL)) == -1) {
            perror("accept error");
            continue;
        }

        while ( (rc=read(cl,buf,sizeof(buf))) > 0) {
            printf("read %u bytes: %.*s\n", rc, rc, buf);
        }
        if (rc == -1) {
            perror("read");
            exit(-1);
        }
        else if (rc == 0) {
            printf("EOF\n");
            close(cl);
        }
    }

    return 0;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-05-09 18:24:54

如果您想要在同一个进程中使用三个侦听套接字,则必须使它们具有独特性。在AF_INET家族中,您可以通过bind(2)-ing不同的端口来实现这一点,而在AF_UNIX家族中,您可以使用不同的路径来完成这一任务。

还有你的台词:

代码语言:javascript
复制
char *socket_path = "\0hidden";

至少有两个问题:

  • 赋值右侧的字符串文本的类型是const char[8],它衰变为const char*指针类型,而不是char*类型。使左手边const char*。此外,编译具有更高的警告级别,如-Wall -pedantic,以获得编译器的帮助。
  • 字符串开头的零字节使strncpy(3)不复制任何东西,因为它是strncpy(3)

创建一个函数,该函数以UNIX path作为参数,并创建、绑定和标记套接字为侦听,并返回创建的套接字描述符。调用它三次--您有三个侦听UNIX套接字。在它们上设置select(2)以便读取--这将在客户端连接到达时告诉您。此时,在活动套接字上调用accept(2)以获得连接的客户端套接字,该套接字与侦听套接字本身是分开的。

票数 3
EN

Stack Overflow用户

发布于 2015-05-09 19:58:46

好吧,既然select,is,而且一直是我最喜欢的Unix,我决定做一些小事情,在我看来,这就是你想要的。

我无耻地从这里获取了服务器和客户端的代码:sockets.html

当然,为了满足您的需要,我做了一些小小的修改,让我们看看:

服务器c:

代码语言:javascript
复制
#include <stdio.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>

char *socket_path = "/tmp/socket";

int main() {
  int fd, i;
  int clients[10], num_clients;
  fd_set read_set;
  char buf[100];

  struct sockaddr_un addr;

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

  unlink(socket_path);

  memset(&addr, 0, sizeof(addr));
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);

  if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
    perror("bind error");
    exit(-1);
  }

  if (listen(fd, 5) == -1) {
    perror("listen error");
    exit(-1);
  }

  num_clients = 0;

  while (1) {
    FD_ZERO(&read_set);
    FD_SET(fd, &read_set);

    for (i = 0; i < num_clients; i++) {
      FD_SET(clients[i], &read_set);
    }

    select(fd + num_clients + 1, &read_set, NULL, NULL, NULL);

    if (FD_ISSET(fd, &read_set)) {
      if ( (clients[num_clients++] = accept(fd, NULL, NULL)) == -1) {
        perror("accept error");
        continue;
      }
      printf("we got a connection!\n");
    }

    for (i = 0; i < num_clients; i++) {
      if (FD_ISSET(clients[i], &read_set)) {
        read(clients[i], buf, sizeof(buf));
        printf("client %d says: %s\n", i, buf);
      }
    }
  }
}

客户。c:

代码语言:javascript
复制
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char *socket_path = "/tmp/socket";

int main(int argc, char *argv[]) {
  struct sockaddr_un addr;
  char buf[100];
  int fd,rc;

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

  memset(&addr, 0, sizeof(addr));
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);

  if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
    perror("connect error");
    exit(-1);
  }

  while( (rc=read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
    printf("writing\n");
    *index(buf, '\n') = 0;

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

  return 0;
}

好的,这很容易操作,您只需在一个终端中启动服务器,然后打开另外几个终端并解雇几个客户端。

在我的电脑上运行我得到:

代码语言:javascript
复制
exe@atreides:~/tmp$ ./server 
we got a connection!
client 0 says: Hello!
we got a connection!
client 1 says: Hey man!

同一时间的另一个终点站:

代码语言:javascript
复制
exe@atreides:~/tmp$ ./client 
Hey man!
writing

在另一篇中:

代码语言:javascript
复制
exe@atreides:~/tmp$ ./client 
Hello!
writing

所有这些背后的神奇之处在于正确使用套接字并进行选择。

首先,您需要一个服务器套接字,即接受连接的套接字。

一旦绑定到服务器套接字,让它成为Unix套接字或网络套接字,您就可以通过接受该套接字上的连接将套接字绑定到客户端。每个客户端都会获得一个新的套接字号。

然后,将这些套接字、服务器套接字和客户端套接字添加到fd_set中,并将其传递给select。Select将同时侦听所有套接字,并将已接收数据的套接字留在集合中。

现在,您可以迭代集合,查看哪些套接字是热的,并且,您在那里!

还有一件事,我想这让你很困惑,所有客户端都连接到同一个服务器套接字地址(文件)。是的,就像很多进程打开同一个文件,同时.但是这不是一个普通的文件,而是一个Unix套接字。:)

玩得开心,好运!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30143335

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档