linux C socket

  socket套接字和管道同样可以提供进程内通信。但套接字更胜一筹,不同的进程可以跨越不同的主机(说白了,支持网络通信)。使用套接字的知名程序:telnet、rlogin、ftp等。

  你需要知道的一些基本原理:

  使用socket时必须指定通信的类型和协议。

  通信类型决定了以下内容:1、数据传输的基本单元(有的会打包传输,有的作为一个结构体);2、数据是否可丢失,数据传输的可靠性:(有的数据丢失一两个便不可读了,有的数据如视频不受太大影响);3、是一对一的通信还是一对多的通信。

  每一个socket必须有一个命名空间,命名空间一般以PF_开头,AF_开头的符号名指定命名空间的地址格式。

你需要了解的协议内容

  要让两个socket能够通信,必须指定相同的协议。

  协议和命名空间、通信风格是绑定的。比如TCP协议只能用在stream风格的通信中,Internet的命名空间中。对于指定的命名空间,请使用默认协议(不同的协议、命名空间组合可能会出错)

  

SOCKET几种通信风格:

int SOCK_STREAM: 提供可靠的通信方式。有连接。

int SOCK_DGRAM: 和SOCK_STREAM相反,使用的是不可靠通讯方式。无连接,每一个数据包都必须指定地址。一般来说,丢包的时候需要重发数据包。

int SOCK_RAW:  这种风格允许我们访问底层网络协议和接口,一般来讲我们不需要使用这种风格。

 

SOCKET地址:

  实际上Socket地址就是socket的名字。在这里地址和名字是同义词。只有把地址和socket绑定后,我们才可以使用socket通信。

网络接口名:

  每一个网络接口都有个名字如:lo、eth0。但在计算机内部,我们通过索引来使用接口。

#include <net/if.h>
size_t IFNAMESIZE    //常量:定义了保存接口名的最大buffer大小。(包含了最后zero 结束字节)
unsigned int if_nametoindex (const char *ifname)
//通过接口名返回该接口的索引号,如果不存在该接口名则返回0。也可以用来判断一个接口是否存在。
char * if_indextoname (unsigned int ifindex, char *ifname)
//将接口索引号ifindex和接口名ifname映射起来。如果索引无效,返回空指针,否则返回接口名。
struct if_nameindex
//用来保存某个接口的信息。

/*成员如下:*/

unsigned int if_index
//接口索引

char *if_name
//接口名(以NULL结尾)
struct if_nameindex * if_nameindex(void)
//返回一个if_nameindex结构体的数组(包含了所有的网络接口)。结束标志:接口索引为0,接口名为空指针。
//返回的结构体必须用if_freenameindex释放
void if_freenameindex (struct if_nameindex *ptr)
//解释如上

 

本地命名空间:

  符号名为PF_LOCAL。本地命名空间也被称之为Unix域套接字。另外一个名字是file namespace(socket 地址常被实现为文件名)

  本地socket无法被其他机器连接(即便其他机器共享了包含本地socket的文件系统)。其他机器可以共享的文件系统查看到scoket文件,但无法连接。关闭本地命名空间的socket,建议同时删除socket文件。本地命名空间只支持一种协议(不管通信风格),协议号是0。

#include <sys/socket.h>
int PF_LOCAL
int PF_UNIX
int PF_FILE

以上几个都是宏常量,而且都是同义词。这些常量用来指定本地命名空间。

#incude <sys/un.h>

struct sockaddr_un {
    short int sun_family;
    char sun_path[108];
}

 

sun_family:标志了地址族和socket 地址的格式。在本地命名空间中,使用AF_LOCAL。

sun_path[108]:socket使用的文件名(很奇怪为何是108个字节,理查德·马修·斯托曼推荐使用alloca来申请适当大小的空间存储文件名。并将该数组长度设置为0)

int SUN_LEN(struct sockaddr_un *ptr)

 SUN_LEN是宏定义的函数,用来计算本地命名空间中socket地址的长度。实际为结构体sockaddr_un的大小。

 

创建一个本地socket实例:

#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>

int make_named_socket (const char *filename)
{
    struct sockaddr_un name;
    int sock;
    size_t size;
    
    /* Create the socket */
    sock = socket (PF_LOACAL, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        perror ("socket");
        exit (EXIT_FAILURE);
    }

    /*Bind a name to the socket.*/
    name.sun_family = AF_LOCAL;
    strncpy (name.sun_path, filename, sizeof (name.sun_path));
    name.sun_path[sizeof(name.sun_path)-1] ='\0';

    /* The size of the address is the 
    offset of the start of the filename,
    plus its length (not including the terminating null byte).
    Alternatively you can just do:
    size = SUN_LEN(&name);
    */
    size = (offsetof (struct sockaddr_un, sun_path)) + strlen (name.sun_path));

    if (bind (sock, (struct sockaddr_un *) &name, size) < 0)
    {
        perror ("bind");
        exit (EXIT_FAILURE);
    }

    return sock;

}

 

posted @ 2016-08-08 18:21  三复苏  阅读(1737)  评论(0编辑  收藏  举报