粉丝不过w

socket 定义

        socket :建立在传输层之上为应用开发人员提供的网络数据传输的接口, 是一种文件描述符,如:请示要尚方宝剑,这样我就可以在皇上的朝廷上 为所欲为

       Socket 类似于打开文件的函数调用—Socket(),该函数返回一个整型的Socket 描述符,然后 连接建立数据传输等操作都是通过该 Socket 描述符实现,如:我要为所欲为的时候,那必须要拿到这个尚方宝剑,这样我就可以纵横网络

   socket 类型

       

         流式 socket—SOCK_STREAM(面向连接的 TCP 服务应用) 和数据报式

 字节序

        计算机数据存储有两种字节优先顺序: 高位字节优先( 大端 )和 低位字节优先( 小端 ),如:皇上想要身材高的妃子先来,还是要身材娇小的妃子先来

以 int a = 0x 053010

      大端:

字节号 0 1 2
数据 05 30 10

      小端:

字节号 0 1 2
数据 10 30 05

判断大小端机:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    if(isLittleEndian())
    {
        printf("Little Endian\n");
    }
    else
    {
        printf("Big Endian\n");
    }
    return 0;
}
int isLittleEndian()
{
    unsigned short i = 1;

    return(1 == *((char *)&i));
}

      网络传输数据以网络字节序(高位字节优先顺序)来传输的,所以 数据发送端要将数据变为网络字节序,在接收端要将网络字节序变成主机字节序,如:皇上在上朝,要高的妃子先来,但后宫是以低的优先,那从后宫到朝上就要变成高的妃子优先,但朝上到后宫就要变成低的妃子

      字节顺序转换函数:

//Host to Network Short
htons()
// Host to Network long
htonl()
// Network to Host Short
ntohs()
// Network to Host Long
ntohl()

       h:" host " , n :" network ", s :" short ", l : " long " 

套接口地址结构

//通用套接口地址
struct sockaddr
{
    unsigned short sa_family; /* 地址族, AF_xxx */
    char sa_data[14];         /* 14 字节的协议地址 */
};
//常用套接口地址
struct sockaddr_in
{                                //“in” 代表“Internet”
    short int sin_family;        /* 地址族,AF_xxx */
    unsigned short int sin_port; /* 端口号 */
    struct in_addr sin_addr;     /* IP 地址 */
    unsigned char sin_zero[8];   /* 填充 0 以保持与 struct sockaddr 同样大小 */
};
// 专门用来存储 IP 地址
struct in_addr
{
    unsigned long s_addr;
};

服务名称数据结构

truct hostent
{
    char *h_name;       /* 主机的正式名称 */
    char *h_aliases;    /* 主机的别名 */
    int h_addrtype;     /* 主机的地址类型 AF_INET*/
    int h_length;       /* 主机的地址长度 对于 IP4 是 4 字节 32 位*/
    char **h_addr_list; /* 主机的 IP 地址列表 */
};

#define h_addr h_addr_list[0]     /* 主机的第一个 IP 地址*/

socket 通信原理

socket 编程函数

    打开套接字

#include <sys/socket.h>

/*
 *function:
 *  为网络通讯做基本的准备
 *parameter:
 *  domain: 通讯协族 AF_UNIX  AF_INET
 *  type:  通讯协议
 *    SOCK_STREAM  TCP 协议,按顺序的,可靠,双向,面向连接的比特
 *    SOCK_DGRAM   UDP 协议,定长的,不可靠,无连接的通信
 *    SOCK_RAW     原始套接字,直接访问 IP 协议
 *  rotocol: 指定 type,填 0 
 *return:
 *  成功: 文件描述符
 *  失败: -1
 */
int socket(int domain, int type,int protocol)

   绑定套接字

/*
 *function:
 *  本地的端口同 socket 返回的文件描述符捆绑在一起
 *marapeter:
 *  sockfd:   socket 调用返回的文件描述符
 *  addrlen:  sockaddr 结构的长度
 *  my_addr:  一个指向 sockaddr 的指针
 *return:
 *  成功: 0
 *  失败: -1
 */
int bind(int sockfd, struct sockaddr *my_addr, int addrlen)

监听 Listen

/*
 *function:
 *  bind 的文件描述符变为监听套接字
 *parameter:
 *  sockfd: bind 后的文件描述符
 *  backlog:设置请求排队的最大长度
 */
int listen(int sockfd,int backlog)

接收(accept)

/*
 *parameter:
 *  sockfd:是 listen 后的文件描述符
 *return:
 *  成功: 返回最后的服务器端的文件描述符
 *  失败: -1
 *note:
 *  服务器端会一直阻塞到有一个客户程序发出了连接
 */
int accept(int sockfd, struct sockaddr *addr, int *addrlen);

连接(connect)

/*
 *function:
 *  客户端用来同服务端连接
 *parameter:
 *  sockfd:    socket 返回的文件描述符
 *  serv_addr: 储存了服务器端的连接信息, sin_add 是服务端的地址
 *  addrlen:   serv_addr 的长度
 *return:
 *  成功: 0, sockfd 是同服务端通讯的文件描述符
 *  失败: -1
 */
int connect(int sockfd, struct sockaddr * serv_addr,int addrlen)

面向连接的读写数据函数

   Send()函数

/*
 *parameter:
 *  sockfd: 传输数据的 socket 描述符
 *  msg:   一个指向要发送数据的指针
 *  len :  数据的长度,单位:字节
 *  flags: 一般为 0
 *return:
 *  实际上发送出的字节数
 */
int send(int sockfd, const void *msg, int len, int flags);

    recv()函数

/*
 *parameter:
 *  sockfd: 接受数据的 socket 描述符
 *  buf:    存放接收数据的缓冲区
 *  len :   缓冲的长度
 *  flags:  置为 0
 *return:
 *  成功:实际上接收的字节数
 *  错误:-1
 */
int recv(int sockfd, void *buf, int len, unsigned int flags);

面向无连接的读写数据函数

     无连接的数据报 socket 方式下,由于本地 socket 并没有与远端机器建立连接,所以在发送数据时要指指明的地址,如:皇上去某妃子后宫,并没有要巍公公通报后宫,皇上要去花妃子后宫,这样可能导致花妃子没有化妆,就失宠

sendto()函数 

/*
 *parameter:
 *  to: 目地机的 IP 地址和端口号信
 *  tolen: sizeof (struct sockaddr)
 *return:
 *  成功:实际发送的数据字节长度
 *  失败:-1
 */
int sendto(int sockfd, 
           const void *msg,
           int len,
           unsigned int flags, 
           const struct sockaddr *to, 
           int tolen);

recvfrom()函数

/*
 *parameter:
 *  from:源机的 IP 地址及端口号
 *  fromlen: sizeof (struct sockaddr)
 *return:
 *  成功:接收到的字节数
 *  失败:-1
 */
int recvfrom(int sockfd,
             void *buf,
             int len,
             unsigned int lags,
             struct sockaddr *from,
             int *fromlen)

面向连接的读写数据函数

        close()函数来释放该 socket,停止在该socket 上的任何数据操作: close(sockfd);如:看见花妃子这个样子,皇上拔腿就跑呀,以后再也不来了

      shutdown()函数来关闭该 socket。 该函数允许你只停止在某个方向上的数据传输, 而一个方向上的数据传输继续进行。如:皇上看见花妃子的样子,皇上扫兴呀,然后要花妃子化妆好了来朕的寝宫

     

/*
 *parameter:
 *  how:
 *    0: 不允许继续接收数据
 *    1: 不允许继续发送数据
 *    2: 不允许继续发送和接收数据
 *return:
 *  成功:0
 *  失败:-1
 */
int shutdown(int sockfd,int how);

DNS——域名服务相关函数

    由于 IP 地址难以记忆和读写,所以为了读写记忆方便,人们常常用域名来表示主机,这就需要进行域名和 IP 地址的转换。如:皇上的妃子很多,皇上记不住呀,就叫的小花,小白,小绿.....

#define h_addr h_addr_list[0] /*在 h-addr-list 中的第一个地址*/

struct hostent
{
    char *h_name;        /* 主机的官方域名 */
    char **h_aliases;    /* 一个以 NULL 结尾的主机别名数组 */
    int  h_addrtype;     /* 返回的地址类型,在 Internet 环境下为 AF-INET */
    int  h_length;       /* 地址的字节长度 */
    char **h_addr_list;  /* 一个以 0 结尾的数组,包含该主机的所有地址*/
};

/*
 *return:
 *  成功:指向 struct hosten 的指针
 *  失败:-1
 *note:
 *  herror(): 输出错误信息
 */
struct hostent *gethostbyname(const char *name);