我正在尝试创建一个server.c文件,该文件支持3个套接字,这些套接字由3个客户端类表示: client1、client2、client3。
在我的server.c文件中,我目前在互联网上找到了这个代码。
如果我想让它有3个插座。我想使用select()命令查看3个客户端的写活动。我的问题是如何使用它来支持3个套接字。
我可以将这3个客户端绑定到服务器可以监听的3个套接字上吗?如果是这样,服务器如何分别侦听这3个套接字?有可能是数组?
#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;
}发布于 2015-05-09 18:24:54
如果您想要在同一个进程中使用三个侦听套接字,则必须使它们具有独特性。在AF_INET家族中,您可以通过bind(2)-ing不同的端口来实现这一点,而在AF_UNIX家族中,您可以使用不同的路径来完成这一任务。
还有你的台词:
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)以获得连接的客户端套接字,该套接字与侦听套接字本身是分开的。
发布于 2015-05-09 19:58:46
好吧,既然select,is,而且一直是我最喜欢的Unix,我决定做一些小事情,在我看来,这就是你想要的。
我无耻地从这里获取了服务器和客户端的代码:sockets.html
当然,为了满足您的需要,我做了一些小小的修改,让我们看看:
服务器c:
#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:
#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;
}好的,这很容易操作,您只需在一个终端中启动服务器,然后打开另外几个终端并解雇几个客户端。
在我的电脑上运行我得到:
exe@atreides:~/tmp$ ./server
we got a connection!
client 0 says: Hello!
we got a connection!
client 1 says: Hey man!同一时间的另一个终点站:
exe@atreides:~/tmp$ ./client
Hey man!
writing在另一篇中:
exe@atreides:~/tmp$ ./client
Hello!
writing所有这些背后的神奇之处在于正确使用套接字并进行选择。
首先,您需要一个服务器套接字,即接受连接的套接字。
一旦绑定到服务器套接字,让它成为Unix套接字或网络套接字,您就可以通过接受该套接字上的连接将套接字绑定到客户端。每个客户端都会获得一个新的套接字号。
然后,将这些套接字、服务器套接字和客户端套接字添加到fd_set中,并将其传递给select。Select将同时侦听所有套接字,并将已接收数据的套接字留在集合中。
现在,您可以迭代集合,查看哪些套接字是热的,并且,您在那里!
还有一件事,我想这让你很困惑,所有客户端都连接到同一个服务器套接字地址(文件)。是的,就像很多进程打开同一个文件,同时.但是这不是一个普通的文件,而是一个Unix套接字。:)
玩得开心,好运!
https://stackoverflow.com/questions/30143335
复制相似问题