※
unix域套接字实际上不是一个实际的协议,他只是在同一台主机上客户和服务器之间通信时,使用与在不同主机上客户和服务器间通信时相同的API
unix域套接字分为两种:字节流套接字和数据报套接字
unix域套接字的好处:
1 在同一台主机上进行通信时,是不同主机间通信的两倍
2 unix域套接口可以在同一台主机上,不同进程之间传递套接字描述符
3 unix域套接字可以向服务器提供客户的凭证(用户id或者用户组id)
unix域套接字使用的地址通常是文件系统中一个文件路径(套接口文件:APUE中的4.3节文件类型,是以s开头的),这些文件不是不同的文件,只能作为域套接字通信,不能读写
并且是以s开头的文件
unix域套接字的地址结构是:
-
struct sockaddr_un
-
{
-
uint8_t sun_len;
-
sa_family_sun_family;
-
char sun_path[104];
-
}
int socketpair(int family, int type, intprotocol, int sockfd[2]);
这个函数创建两个互相连接的套接字(socketfd[2])family 是AF_LOCAL, type可以是SOCK_STREAM (字节流)或者SOCK_DGRAM(数据报),协议是0,之后就能够或者两个互相连接的套接字
以SOCK_STREAM调用的socketpair函数得到的套接字叫做流管道(stream pipe),是全双工的,就是这两个套接字是可读可写的
※
1在unix域套接字进行bind的时候建立套接口文件,其默认的权限值是0777,并被当前的umask修改,看上图就知道,umask是0022 的到的文件权限是0755
2关于bind创建文件中地址参数 sockaddr_un 中的sun_path需要是绝对路径,这样才能不用考虑相对的概念。防止客户端程序也用相对路径,但是和服务器不在同一个目录的考虑
3 connect中的地址中的路径名必须是套接口文件,而且已经被服务端绑定的,以下情况会出错:1 文件路径存在但是不是套接口文件2 路径名存在且是套接口文件,但是没有和该文件绑定的套接口3 就是type必须和服务器相同
4 connect连接unix套接口的时候的权限检查和open函数一样的
5 unix域字节流套接口和TCP一样都给进程提供一个无记录边界的字节流接口
6 unix域套接口connect发现等待队列满了,就直接返回ECONNREFUSRD错误,说连接拒绝错误
7 unix域数据报套接口和UDP一样提供一个保留记录边界的不可靠数据报服务
unix域套接字的客户端:
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#define MAX_SEND 1025
-
#define UNIX_PATH "/tmp/sinfor"
-
-
void dump_unix(int sock_fd)
-
{
-
char tmp[MAX_SEND] = {0};
-
char recv[MAX_SEND] = {0};
-
while(fgets(tmp, MAX_SEND, stdin) != NULL)
-
{
-
write(sock_fd, tmp, strlen(tmp));
-
read(sock_fd, recv, MAX_SEND);
-
printf("data : %s\n", recv);
-
bzero(tmp,MAX_SEND);
-
bzero(recv, MAX_SEND);
-
}
-
}
-
int main(int argc, char** argv)
-
{
-
int conn_sock = socket(AF_LOCAL, SOCK_STREAM, 0);
-
if(conn_sock == -1)
-
{
-
perror("socket fail ");
-
return -1;
-
}
-
struct sockaddr_un addr;
-
bzero(&addr, sizeof(addr));
-
addr.sun_family = AF_LOCAL;
-
strcpy((void*)&addr.sun_path, UNIX_PATH);
-
if(connect(conn_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
-
{
-
perror("connect fail ");
-
return -1;
-
}
-
dump_unix(conn_sock);
-
close(conn_sock);
-
return 0;
-
}
unix域套接字的服务器;
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#define MAX_RECV 1025
-
#define UNIX_SERV_PATH "/tmp/sinfor"
-
void client_dump(int sock_fd)
-
{
-
char rec[MAX_RECV] = {0};
-
int size;
-
while((size = read(sock_fd, rec, MAX_RECV)) != 0)
-
{
-
printf("**********1111************\n");
-
printf("recv data is %s\n", rec);
-
write(sock_fd, rec, size);
-
}
-
}
-
void sig_son(int num)
-
{
-
printf("son is %d\n", getpid());
-
wait(NULL);
-
-
}
-
int main(int argc, char** argv)
-
{
-
int acc_sock, dump_sock;
-
acc_sock = socket(AF_LOCAL, SOCK_STREAM, 0);
-
if(acc_sock == -1)
-
{
-
perror("socket func fail ");
-
return -1;
-
}
-
struct sockaddr_un ser_addr, cli_addr;
-
ser_addr.sun_family = AF_LOCAL;
-
strcpy(ser_addr.sun_path, UNIX_SERV_PATH);
-
unlink(UNIX_SERV_PATH);
-
bind(acc_sock, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
-
listen(acc_sock, 5);
-
signal(SIGCHLD, sig_son);
-
while(1)
-
{
-
int len = sizeof(cli_addr);
-
dump_sock = accept(acc_sock, (struct sockaddr*)&cli_addr, &len);
-
if(dump_sock == -1)
-
{
-
if(errno == EINTR)
-
{
-
continue;
-
}
-
else
-
{
-
perror("accept fail");
-
return -1;
-
}
-
}
-
if(fork() == 0)
-
{
-
close(acc_sock);
-
client_dump(dump_sock);
-
close(dump_sock);
-
exit(0);
-
}
-
close(dump_sock);
-
}
-
close(acc_sock);
-
return 0;
-
}
这章还有用户认证和描述符通过unix套接字在不同进程之间传递,看完了,太累了,就不写了,有兴趣的自己看看unp吧
阅读(1300) | 评论(0) | 转发(0) |