我开始使用unix套接字,并且首先偶然发现了打开这个新创建的文件的问题。我非常确定open()
函数应该完成这项工作,但事实并非如此。我的同事说应该通过connect()
函数打开一个unix套接字,所有的工作都应该像网络一样考虑。
因此,似乎我不能创建一个套接字,并退出程序(就像我一样),唯一的服务器程序应该是创建套接字的程序。但我无法理解:为什么文件系统中的套接字在程序创建者退出时不会被销毁?对我来说,这看起来肯定是一种以某种方式将应用程序连接到此套接字,并使应用程序成为服务器的方法。
下面是一个代码,仅用于说明:我执行此代码(这将创建一个名为 filename 的unix套接字),然后退出。
char* CreateSocket(const char* filename){
if(107 <= strlen(filename)){//if the file name too long, error
char* Buf = new char[sizeof(TOOLONGFILENAME)+sizeof(int)];
sprintf(Buf, TOOLONGFILENAME, strlen(filename) );
Buf[sizeof(TOOLONGFILENAME)+sizeof(int)] = 0;
return Buf;
}
fdSock = socket(AF_UNIX, SOCK_DGRAM, 0);
if(0 > fdSock){
char* p = strerror(errno);
char* buf = new char[strlen(p)];
strcpy(buf,p);
return buf;
}
sockaddr_un server;
server.sun_family = AF_UNIX;
strcpy(server.sun_path, filename);
if(0 > bind(fdSock, (sockaddr*)&server, sizeof(sockaddr_un))){
char* p = strerror(errno);
char* buf = new char[strlen(p)];
strcpy(buf,p);
return buf;
}
return 0;
}
答案 0 :(得分:1)
我无法完全理解你的问题。我认为你不理解socket()
机制。
我会解释。这里的套接字类似于指针或文件描述符。
有两种不同的程序:服务器和客户端。他们不依赖。服务器打开一个套接字并等待连接。客户端打开其OWN套接字,连接到远程地址。服务器处理连接。发生这两个程序之间的数据交换,然后(如果需要)终止连接。
以下是TCP / IP最简单的客户端和服务器程序的示例,它们显示了socket()
机制的工作原理。
服务器代码:
void * server (void)
{
int listenfd, connfd;
struct sockaddr_in servaddr;
socklen_t lenkeepalive;
struct net_pack recvline;
int i,n;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
listen(listenfd, LISTENQ);
int keepalive =1;
lenkeepalive = sizeof(keepalive);
if(setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, lenkeepalive) < 0)
{
perror("server: setsockopt()");
shutdown(listenfd,SHUT_RDWR);
close(listenfd);
exit(EXIT_FAILURE);
}
pthread_create (NULL, NULL, (void *)server_send, NULL);
for(;;)
{
if(connfd = accept(listenfd, (SA *) NULL, NULL)>0){
bzero(&recvline, sizeof(recvline));
//try get msg from connected client
while ( (recv(connfd, &recvline, MAXLINE, 0)) > 0)
{
printf("server: recvline.msg - %s\n",recvline.msg);
bzero(&recvline, sizeof(recvline));
/*
...
*/
// send answ
encode(&recvline,"hello2",H); //make a msg
if(send(connfd, &recvline, (strlen(recvline.msg)+4), MSG_NOSIGNAL); < 0)
{
printf("server_send: send error %d (%s)\n",errno, strerror(errno));
}
//discard client connection
shutdown(connfd,SHUT_RDWR);
close(connfd);
}
}
}
// some error occurs
perror("server: accept()");
shutdown(listenfd,SHUT_RDWR);
close(listenfd);
return 0;
}
客户端代码
void * client (void)
{
socklen_t lenkeepalive;
int sockfd, keepalive, n;
struct net_pack recvline; //pack for msg
struct sockaddr_in servaddr;
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{printf("client: socket error %d ( %s )\n ",errno, strerror(errno));}
keepalive = 1;
lenkeepalive = sizeof(keepalive);
if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, lenkeepalive) < 0)
{
perror("client: setsockopt()");
shutdown(sockfd,SHUT_RDWR);
close(sockfd);
exit(EXIT_FAILURE);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
if (inet_pton(AF_INET, servip, &servaddr.sin_addr) <= 0)
printf("client: inet_pton error for %s\r\n", servip);
if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
{
printf("client: connect to %s error %d ( %s )\r\n",servip, errno, strerror(errno));
}
else
{
// send a msg
encode(&recvline,"hello",H); //make a msg
n = send(sockfd, &recvline, (strlen(recvline.msg)+4), MSG_NOSIGNAL);
if(n < 0)
{printf("client: i cannot send, error %d (%s)\n",errno, strerror(errno));}
bzero(&recvline, sizeof(recvline));
//recv data from server
while( (n = recv(sockfd, &recvline, MAXLINE, 0)) >= 0)
{
printf("client: recvline.msg - %s\n",recvline.msg);
bzero(&recvline, sizeof(recvline));
}
}
// some error occurs
perror("client: recv()");
shutdown(sockfd,SHUT_RDWR);
close(sockfd);
return 0;
}
在你的情况下,你应该使用sockaddr_un而不是sockaddr_in,以及一些必要的标志,如AF_UNIX
,SOCK_DGRAM
和其他。
答案 1 :(得分:1)
W的绝妙书“套接字网络API:UNIX®网络编程第1卷,第三版” 中的短引用。理查德·史蒂文斯;比尔·芬纳Andrew M. Rudoff 。
第15章。示例:Unix域套接字的绑定。
首先删除路径名。我们绑定到套接字的路径名是命令行参数。但是,如果文件系统中已存在路径名,则绑定将失败。因此,如果路径名已经存在,我们调用unlink删除该路径名。如果不存在,则取消链接将返回错误,我们将忽略该错误。
实际上,您可以使用该路径来检测服务器是否存在。服务器终止时,必须删除文件以使客户端了解没有服务器可以读取传入的连接。例如, Docker 就是这样工作的:如果没有生成守护程序,则系统中没有docker.sock
文件。
答案 2 :(得分:0)
要充当面向连接的服务器,应用程序会创建一个套接字,然后绑定,然后侦听以获取传入连接。
然后,对于每个传入连接,应用程序接受并为其提供服务。
每项操作都有一项功能:socket
,bind
,listen
和accept
。
此处必须执行所有步骤,并且所有步骤都必须在同一应用程序中执行。你不能创建一个绑定套接字,然后让其他程序使用它。
面向连接的客户端需要创建一个套接字,然后调用connect
。
面向数据报的通信没有连接,不使用listen
,accept
和connect
。
答案 3 :(得分:0)
我没有研究实际的理由,但是我可以假设的是套接字API本身并不关心文件。
您可以将其与通过IP连接进行比较。您绑定到端口,然后断开连接,但是该端口始终存在,并且永远不会被删除。
对于UNIX套接字,创建不存在的文件是有意义的(尽管我不认为套接字API本身会创建文件,而是请求其使用,然后在文件上自动创建文件-也许操作系统),但是从API的角度来看,删除该文件没有工作,只是不再使用它。