sockaddr
struct sockaddr {
unsigned short sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
};
sa_family是地址家族,一般都是“AF_xxx”的形式。好像通常大多用的是都是AF_INET。
sa_data是14字节协议地址。此数据结构用做bind、connect、recvfrom、sendto等函数的参数,指明地址信息。
但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构sockaddr_in
sockaddr_in
sockaddr_in(在netinet/in.h中定义):
struct sockaddr_in {
short int sin_family; /* Address family */
unsigned short int sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
unsigned char sin_zero[8]; /* Same size as struct sockaddr */
};
struct in_addr {
unsigned long s_addr;
};
typedef struct in_addr {
union {
struct{
unsigned char s_b1,
s_b2,
s_b3,
s_b4;
} S_un_b;
struct {
unsigned short s_w1,
s_w2;
} S_un_w;
unsigned long S_addr;
} S_un;
} IN_ADDR;
sin_family指代协议族,在socket编程中只能是AF_INET
sin_port存储端口号(使用网络字节顺序)
sin_addr存储IP地址,使用in_addr这个数据结构
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
s_addr按照网络字节顺序存储IP地址
sockaddr_in和sockaddr是并列的结构,指向sockaddr_in的结构体的指针也可以指向
sockadd的结构体,并代替它。也就是说,你可以使用sockaddr_in建立你所需要的信息,
在最后用进行类型转换就可以了
bzero((char*)&mysock,sizeof(mysock));//初始化
mysock结构体名
mysock.sa_family=AF_INET;
mysock.sin_addr.s_addr=inet_addr("192.168.0.1");
等到要做转换的时候用:
(struct sockaddr*)mysock
sockaddr_un
进程间通信的一种方式是使用UNIX套接字,人们在使用这种方式时往往用的不是网络套接字,而是一种称为本地套接字的方式。这样做可以避免为黑客留下后门。
创建
使用套接字函数socket创建,不过传递的参数与网络套接字不同。域参数应该是PF_LOCAL或者PF_UNIX,而不能用PF_INET之类。本地套接字的通讯类型应该是SOCK_STREAM或SOCK_DGRAM,协议为默认协议。例如:
sockfd = socket(PF_LOCAL, SOCK_STREAM, 0);
绑定
创建了套接字后,还必须进行绑定才能使用。不同于网络套接字的绑定,本地套接字的绑定的是struct sockaddr_un结构。struct sockaddr_un结构有两个参数:sun_family、sun_path。sun_family只能是AF_LOCAL或AF_UNIX,而sun_path是本地文件的路径。通常将文件放在/tmp目录下。例如:
struct sockaddr_un sun;
sun.sun_family = AF_LOCAL;
strcpy(sun.sun_path, filepath);
bind(sockfd, (struct sockaddr*)&sun, sizeof(sun));
监听
本地套接字的监听、接受连接操作与网络套接字类似。
连接
连接到一个正在监听的套接字之前,同样需要填充struct sockaddr_un结构,然后调用connect函数。
连接建立成功后,我们就可以像使用网络套接字一样进行发送和接受操作了,甚至还可以将连接设置为非阻塞模式。
参考例子代码1
/* 要点:sockaddr_un
* 功能:监听UNIX域socket
* 成功:返回新生成的套接字文件描述符
* 失败:返回-1
*/
int std_listen_unix(const char *socketfile)
{
int fd = 0, len = 0, operate_ret = OPERATE_SUCCESS;
struct sockaddr_un serv;
if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
STD_DEBUG_PRINT("socket failed! %s\n", strerror(errno));
operate_ret = OPERATE_FAILED;
goto ret_lable;
}
unlink(socketfile); /***********************/
len = strlen(socketfile);
if(len > 107)
{
DEBUG_PRINT ("socket file len is too long!");
operate_ret = OPERATE_FAILED;
goto ret_lable;
}
memset (&serv, 0, sizeof(serv));
serv.sun_family = AF_UNIX;
strncpy (serv.sun_path, socketfile, len);
len += offsetof(struct sockaddr_un, sun_path); /**********/
if(bind(fd, (struct sockaddr *)&serv, len) < 0)
{
DEBUG_PRINT ("bind failed!");
operate_ret = OPERATE_FAILED;
goto ret_lable;
}
if(listen(fd, 10) < 0)
{
DEBUG_PRINT ("listen failed!");
operate_ret = OPERATE_FAILED;
goto ret_lable;
}
return (fd); /************************/
ret_lable:
if (fd >= 0)
{
close(fd);
}
return operate_ret;
}
/* 要点:sockaddr_un
* 功能:连接到UNIX域socket
* 成功:返回新生成的套接字文件描述符
* 失败:返回-1
*/
int std_connect_unix(const s8 *socketfile)
{
int sock = 0, ret = 0, opt = 0;
size_t len = 0;
struct sockaddr_un srv_sock;
if( (sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 )
{
DEBUG_PRINT("socket failed!%s\n", strerror(errno));
return OPERATE_FAILED;
}
len = strlen (socketfile);
memset (&srv_sock, 0, sizeof(struct sockaddr_un));
srv_sock.sun_family = AF_UNIX;
strncpy (srv_sock.sun_path, socketfile, len);
len += offsetof (struct sockaddr_un, sun_path);
if((ret = connect(sock, (struct sockaddr *)&srv_sock, len)) < 0 )
{
DEBUG_PRINT ("connect failed: %d\n", ret);
close (sock);
return OPERATE_FAILED;
}
opt = 1;
setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
return sock;
}
参考代码2
//server
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#define PATH "./tt"
int main(int argc ,char *argv[])
{
int sockfd = 0;
struct sockaddr_un addr;
unlink(PATH);
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path,PATH);
unsigned int len = strlen(addr.sun_path) + sizeof(addr.sun_family);
sockfd = socket(AF_UNIX,SOCK_DGRAM,0);
if(sockfd < 0 )
{
perror("socket error");
exit(-1);
}
if(bind(sockfd,(struct sockaddr *)&addr,len) < 0)
{
perror("bind error");
close(sockfd);
exit(-1);
}
printf("Bind is ok\n");
while(1)
{
char recv_buf[20] = "";
recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(struct sockaddr*)&addr,&len);
printf("Recv: %s\n",recv_buf);
}
return 0;
}
//client
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#define PATH "./tt"
int main(int argc,char *argv[])
{
int sockfd = 0;
struct sockaddr_un addr;
bzero(&addr,sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path,PATH);
sockfd = socket(AF_UNIX,SOCK_DGRAM,0);
if(sockfd < 0)
{
perror("socket error");
exit(-1);
}
while(1)
{
static int counter = 0;
char send_buf[20] = "";
counter++;
sprintf(send_buf,"Counter is %d",counter);
int len = strlen(addr.sun_path)+sizeof(addr.sun_family);
sendto(sockfd,send_buf,strlen(send_buf),0,(struct sockaddr*)&addr,len);
printf("Send: %s\n",send_buf);
sleep(1);
}
return 0;
}