Hi-*_*gel 8 c++ unix sockets linux
我第一次使用 unix 套接字,我偶然发现了 unix 套接字文件没有被自动删除的问题。看来,在创建套接字后,我不能只是退出程序,而应该删除套接字文件。
但是为什么套接字文件在创建它的程序退出后没有被破坏?看起来应该有办法以某种方式将应用程序连接到这个剩余的文件,或者为什么它仍然存在?
下面是一个代码来说明(它创建一个unix套接字然后退出):
#include <cstdio>
#include <sys/socket.h>
#include <sys/un.h>
int CreateSocket(const char* filename) {
if (strlen(filename) > sizeof(sockaddr_un::sun_path)) {
puts("Too long filename!");
return -1;
}
int fdSock = socket(AF_UNIX, SOCK_DGRAM, 0);
if(fdSock == -1){
perror("socket");
return -1;
}
sockaddr_un server;
server.sun_family = AF_UNIX;
strcpy(server.sun_path, filename);
if(bind(fdSock, (sockaddr*)&server, sizeof(sockaddr_un)) == -1){
perror("socket");
return -1;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
摘自W. Richard Stevens所著的《The Sockets Networking API: UNIX\xc2\xae Network Programming Volume 1, Third Edition》一书的简短引用;比尔·芬纳;安德鲁·M·鲁道夫。
\n\n第15章。示例:Unix Domain Socket 的绑定。
\n\n\n\n\n首先删除路径名。我们绑定到套接字的路径名是命令行参数。但如果文件系统中已存在该路径名,则绑定将失败。因此,我们调用 unlink 来删除路径名(如果它已经存在)。如果不存在,unlink 将返回一个错误,我们会忽略该错误。
\n
其实,你可以通过该路径来检测服务器是否存在。当服务器终止时,它必须删除一个文件,以使客户端了解没有服务器可以读取传入连接。例如,Docker是这样工作的:如果守护进程没有生成,那么docker.sock系统中就没有文件。
小智 1
我无法完全理解你的问题。我认为你不明白这个socket()机制。我会解释。这里的socket类似于指针或者文件描述符。有两个不同的程序:服务器和客户端。他们不依赖。服务器打开一个套接字并等待连接。客户端打开自己的套接字,连接到远程地址。服务器处理连接。这两个程序之间发生数据交换,然后(如果需要)连接终止。以下是最简单的 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;
}
Run Code Online (Sandbox Code Playgroud)
客户端代码
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;
}
Run Code Online (Sandbox Code Playgroud)
在您的情况下,您应该使用 sockaddr_un 而不是 sockaddr_in,以及一些必要的标志,如AF_UNIX、SOCK_DGRAM等。