Linux套接字编程之sockaddr与sockaddr_in网络套接字,sockaddr_un进程间通信本地套接字

版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/wteruiycbqqvwt/article/details/89604944

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_pathsun_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;
}

猜你喜欢

转载自blog.csdn.net/wteruiycbqqvwt/article/details/89604944