现在的位置: 首页 > 综合 > 正文

Socket编程实践(1)

2017年10月06日 ⁄ 综合 ⁄ 共 3364字 ⁄ 字号 评论关闭

Socket Api基本概念

什么是socket?

    socket可以看成是用户进程内核网络协议栈的编程接口(如下图所示)。

    socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信。

 



 

tcp/ip通信模型

 

 

               C/S模型



 

              B/S模型

 

IPv4套接口地址结构

    IPv4套接口地址结构通常也称为“网际套接字地址结构”,它以“sockaddr_in”命名,定义在头文件<netinet/in.h>中

 

TCP/IP结构:

struct sockaddr_in
{
    uint8_t  sin_len;
    sa_family_t  sin_family;
    in_port_t	sin_port;	//2字节
    struct in_addr	sin_addr;	//4字节
    char sin_zero[8];	//8字节
};

说明:

    sin_len:整个sockaddr_in结构体的长度,在4.3BSD-Reno版本之前的第一个成员是sin_family.

    sin_family:指定该地址家族,在这里必须设为AF_INET

    sin_port:端口

    sin_addrIPv4的地址;

    sin_zero:暂不使用,一般将其设置为0

 

Linux结构(常用):

struct sockaddr_in
{
    sa_family_t    sin_family; /* address family: AF_INET */
    in_port_t      sin_port;   /* port in network byte order */
    struct in_addr sin_addr;   /* internet address */
};

/* Internet address. */
struct in_addr
{
    uint32_t       s_addr;     /* address in network byte order */
};

通用地址结构

    通用地址结构用来指定与套接字关联的地址。(可以支持其他协议)

struct sockaddr
{
	uint8_t  sin_len;
	sa_family_t  sin_family;
	char sa_data[14]; 	//14字节   
};

说明:

    sin_len:整个sockaddr结构体的长度

    sin_family:指定该地址家族

    sa_data:由sin_family决定它的形式。

 

 

字节序

1.大端字节序(Big Endian)

    最高有效位(MSB:Most Significant Bit)存储于最低内存地址处,最低有效位(LSB:Lowest Significant Bit)存储于最高内存地址处。

 

2.小端字节序(Little Endian)

    最高有效位(MSB:Most Significant Bit)存储于最高内存地址处,最低有效位(LSB:Lowest Significant Bit)存储于最低内存地址处。

 

3.主机字节序

    不同的主机有不同的字节序,如x86为小端字节序,Motorola 6800为大端字节序,ARM字节序是可配置的。

 

4.网络字节序

    网络字节序规定为大端字节序

//测试当前系统是否为小端模式
int main()
{
    int data = 0x12345678;  //int = 4字节(32位)
                            //每4个二进制位代表1位十六进制位,
                            //则8位十六进制位代表4*8=32位二进制位
    char *p = (char *)&data;
    printf("%x, %x, %x, %x\n",p[0],p[1],p[2],p[3]);

    //0x78属于低位,如果其放在了p[0](低地址)处,则说明是小端模式
    if (p[0] == 0x78)
    {
        cout << "当前系统为小端模式" << endl;	//x86平台为小端模式
    }
    else if (p[0] == 0x12)
    {
        cout << "当前系统为大端模式" << endl;	//IBM为大端模式
    }

    return 0;
}

 

字节序转换函数(用于端口转换)

  uint32_t htonl(uint32_t hostlong);
  uint16_t htons(uint16_t hostshort);
  uint32_t ntohl(uint32_t netlong);
  uint16_t ntohs(uint16_t netshort);
/**说明:
  h代表(local)host;n代表network;
  s代表short;l代表long;
*/
DESCRIPTION
       The  htonl() function converts the unsigned integer hostlong from host byte order to network byte order.
       The htons() function converts the unsigned short integer hostshort from host  byte  order to network byte order.
       The  ntohl()  function  converts  the unsigned integer netlong from network byte order to host byte order.
       The ntohs() function converts the unsigned short integer netshort from network byte order to host byte order.
       On the i386 the host byte order is Least Significant Byte first, whereas the network byte order, as used on the Internet, is Most Significant Byte first.

//测试转换结果
int main()
{
    int localeData = 0x12345678;
    char *p = (char *)&localeData;

    if (p[0] == 0x78)
    {
        cout << "本地系统为小端模式" << endl;
    }
    else
    {
        cout << "本地系统为大端模式" << endl;
    }

  //将本地字节转换成网络字节
    int inetData = htonl(localeData);
    p = (char *)&inetData;
    if (p[0] == 0x12)
    {
        cout << "网络系统为大端模式" << endl;
    }
    else
    {
        cout << "网络系统为小端模式" << endl;
    }

    cout << localeData << endl;
    cout << htonl(localeData) << endl;

    return 0;
}


地址转换函数(用于IP地址转换)

#include <netinet/in.h>
#include <arpa/inet.h>
  int inet_aton(const char *cp, struct in_addr *inp);
  in_addr_t inet_addr(const char *cp);	
  char *inet_ntoa(struct in_addr in);

in_addr定义如下:

typedef uint32_t in_addr_t;
struct in_addr
{
    in_addr_t s_addr;
};

//实践
int main()
{
    //将点分十进制转换成十进制数
    cout << inet_addr("192.168.139.137") << endl;

    //将十进制数转换成点分十进制形式
    struct in_addr address;
    address.s_addr = inet_addr("192.168.139.137");
    cout << inet_ntoa(address) << endl;

    memset(&address,0,sizeof(address));
    inet_aton("127.0.0.1", &address);
    cout << address.s_addr << endl;
    cout << inet_ntoa(address) << endl;
    return 0;
}

套接字类型

1)流式套接字(SOCK_STREAM)

     提供面向连接的、可靠的数据传输服务,数据无差错,无重复的发送,且按发送顺序接收。

2)数据报式套接字(SOCK_DGRAM)

     提供无连接服务。不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。

3)原始套接字(SOCK_RAW)

抱歉!评论已关闭.