本地套接字示例[来源:Advanced Linux Programming]
要通过套接字连接同一台主机上的进程,可以使用符号常量 PF_LOCAL 和 PF_UNIX所代表的本地命名空间。它们被称为本地套接字(local sockets)或者 UNIX 域套接字(UNIX-domain sockets)。它们的套接字地址用文件名表示,且只在建立连接的时候使用。
套接字的名字在 struct sockaddr_un 结构中指定。你必须将 sun_family 字段设置为 AF_LOCAL 以表明它使用本地命名空间。该结构中的 sun_path 字段指定了套接字使用的路径,该路径长度必须不超过 108 字节。而 struct sockaddr_un 的实际长度应由UN_LENG 宏计算得到。可以使用任何文件名作为套接字路径,但是进程必须对所指定的
目录具有写权限,以便向目录中添加文件。如果一个进程要连接到一个本地套接字,则必须具有该套接字的读权限。尽管多台主机可能共享一个文件系统,只有同一台主机上运行的程序之间可以通过本地套接字通信。
socket-server.c
/*
zzb 2011-11-17 22:30
<<高级Linux编程.pdf>> page101: socket-server.c
功能:本地命名空间套接字服务器
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
int server(int client_socket)
{
int length;
char *text;
if(read(client_socket, &length, sizeof(length)) == 0) // 获取消息长度,保存到length
return 0;
text = malloc(length); // 分配用于保存信息的缓冲区
read(client_socket, text, length);
printf("%s\n", text);
if(!strcasecmp(text, "quit")) // 忽略大小写比较字符串
{
free(text); // 释放缓冲区
return 1;
}
free(text);
return 0;
}
int main(int argc, char *argv[])
{
const char* const socket_name = argv[1];
int sock_fd;
struct sockaddr_un name;
int client_sent_quit_message;
if((sock_fd = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
{
perror("socket");
return 1;
}
name.sun_family = AF_LOCAL;
strcpy(name.sun_path, socket_name);
if(bind(sock_fd, (const struct sockaddr*)&name, SUN_LEN(&name)) == -1)
{
perror("bind");
return 1;
}
if(listen(sock_fd, 5) == -1)
{
perror("listen");
return 1;
}
do
{
struct sockaddr_un client_name;
socklen_t client_name_len;
int client_socket_fd;
client_socket_fd = accept(sock_fd, (struct sockaddr*)&client_name, &client_name_len);
client_sent_quit_message = server(client_socket_fd);
close(client_socket_fd);
}while(!client_sent_quit_message);
close(sock_fd); // 关闭套接字文件
unlink(socket_name); // 删除套接字文件
return 0;
}
socket-client.c
/*
zzb 2011-11-17 22:37
<<高级Linux编程.pdf>> page103: socket-client.c
功能:本地命名空间套接字服务器
*/
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
void write_text(int socket_fd, const char* text)
{
int length = strlen(text) + 1;
write(socket_fd, &length, sizeof(length)); // 写入长度信息
write(socket_fd, text, length); // 写入消息
}
int main(int argc, char *argv[])
{
const char* const socket_name = argv[1]; // 套接字文件路径
const char* const message = argv[2]; // 要发送的消息
int socket_fd;
struct sockaddr_un name;
socket_fd = socket(PF_LOCAL, SOCK_STREAM, 0); // 创建本地套接字
name.sun_family = AF_LOCAL;
strcpy(name.sun_path, socket_name);
connect(socket_fd, (const struct sockaddr*)&name, SUN_LEN(&name)); // 连接套接字
write_text(socket_fd, message); // 向套接字写入数据
close(socket_fd);
return 0;
}
编译运行:
[zcm@socket #78]$make
gcc -g -c -o socket-server.o socket-server.c
gcc -g -o socket-server socket-server.o
gcc -g -c -o socket-client.o socket-client.c
gcc -g -o socket-client socket-client.o
[zcm@socket #79]$./socket-server /tmp/socket
what can you do for me
what are\nyou doing
this program is great
Quit
[zcm@socket #80]$
运行客户端:
[zcm@socket #19]$./socket-client /tmp/socket "what can you do for me"
[zcm@socket #20]$./socket-client /tmp/socket "what are\nyou doing"
[zcm@socket #21]$./socket-client /tmp/socket "this program is great"
[zcm@socket #22]$./socket-client /tmp/socket "Quit"
[zcm@socket #23]$