如何在Objective-C中使用本地域套接字

如何在Objective-C中使用本地域套接字,objective-c,macos,sockets,networking,Objective C,Macos,Sockets,Networking,Objective-C使网络套接字与流一起使用变得非常容易,可以执行以下操作: // Setup comms with the server, assumed to be running on the local host NSHost* host = [NSHost hostWithAddress:@"127.0.0.1"]; NSInputStream *iStream; NSOutputStream *oStream; [NSStream getStreamsToHost:host p

Objective-C使网络套接字与流一起使用变得非常容易,可以执行以下操作:

// Setup comms with the server, assumed to be running on the local host
NSHost* host = [NSHost hostWithAddress:@"127.0.0.1"];

NSInputStream *iStream;
NSOutputStream *oStream;

[NSStream getStreamsToHost:host port:_PORT inputStream: &iStream outputStream: &oStream];
但是,是否可以通过这种方式创建和/或连接到,或者Objective-C是否为此提供了其他类

如果我仍然可以使用NSStream和getStreamsToHost,我将如何指定该文件以及端口号


到目前为止,我在这方面的研究显示了许多使用TCP/IP或UDP的示例,但不是本地域套接字。

对于UNIX域套接字,您不能使用
-getStreamsToHost:port:inputStream:outputStream:
。但是,您可以创建自己的
NSInputStream
NSOutputStream
实例;最简单的方法是利用
CF(读|写)流
NS(输入|输出)流
之间的免费桥接;例如:

struct sockaddr_un sun;

sun.sun_family = AF_UNIX;
strcpy (sun.sun_path, "/path/to/my/socket");
sun.sun_len = SUN_LEN(&sun);

// Server side (naive)
int server_sock = socket (SOCK_UNIX, SOCK_STREAM, 0);
int ret = bind (server_sock, (struct sockaddr *)&sun, sun.sun_len);

listen (server_sock, 1);               // In practice you'd specify more than 1

s = accept (server_sock, NULL, NULL);  // In practice you want to keep calling this

// Client side
int s = socket (SOCK_UNIX, SOCK_STREAM, 0);

int ret = connect (s, (struct sockaddr *)&sun, sun.sun_len);

CFReadStreamRef readStream;
CFWriteStreamRef writeStream;

CFStreamCreatePairWithSocket (kCFAllocatorDefault, s, &readStream, &writeStream);
然后,要获得
NSInputStream
NSOutputStream
,只需执行以下操作即可

NSInputStream *inputStream = (__bridge_transfer NSInputStream *)readStream;
NSOutputStream *outputStream = (__bridge_transfer NSOutputSteram *)outputStream;
显然,在实践中,您可能希望在自己的代码中将上述所有内容封装在函数或方法中。另外,请注意
sockaddr_un
sun_path
成员可能应该有1024个字符,但在标题中似乎只有104个字符(这是一个长期存在的问题,显然要追溯到BSD4.4;有些系统也有其他字符计数)。这离PATH\u MAX还差得远,因此在实践中,您可能希望编写类似的代码

struct sockaddr_un *new_unix_addr (const char *path) {
  size_t len = strlen (path);
  size_t bytes = sizeof (struct sockaddr_un) + len + 1
                 - sizeof (((struct sockaddr_un *)0)->sun_path);
  struct sockaddr_un *pun = (struct sockaddr_un *)malloc (bytes);

  pun->sun_family = AF_UNIX;
  pun->sun_len = bytes;
  memcpy (pun->sun_path, path, len + 1);
  return pun;
}

稍后请记住释放它。

我不确定在
sun\u path
的定义中1024是否意外变成104,在其他平台(Linux、Solaris)上也是104或108。比较一下。@MartinR看起来这是一个很老的意外,然后:-)Unix域套接字可能在Unix系统中允许这么长的路径名之前就存在了。-我也不确定你是否可以简单地分配一个更大的sockaddr_un(你试过了吗?)。这需要内核能够处理更大的路径。POSIX规范声明“应用程序不应该假定sun_path的特定长度,或者假定它可以容纳{u POSIX_path_MAX}个字符(255)。@MartinR没有尝试过它,但我希望如果内核不支持它,它会失败并产生错误代码,这比缓冲区溢出要好。如果它真的支持它,那么它就会起作用。这似乎是一个合理的选择。谢谢,这一切看起来都不错,尽管我在连接到创建的套接字时遇到了问题。我以前用Qt编写过一个程序,它可以创建我可以连接的套接字。该套接字文件具有sxrwxrw-rw-权限,但您发布的代码创建的文件具有srwxr-xr-x权限。两个套接字都属于同一用户和组。我无法远程登录到由上述代码创建的套接字,因为它声明权限被拒绝。你知道为什么权限不同吗?即使我将文件chmod到777,它仍然无法允许连接。