Linux socket 学习

本文主要是介绍在linux socket编程时常用的函数以及结构体类型。

一、主机字节序和网络字节序介绍
1.大端和小端
1)小端字节序:低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
2)大端字节序:高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
通常Inter x86、ARM核采用的是小端模式,Power PC、MIPS UNIX和HP-PA UNIX采用大端模式。

2.主机字节序:不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序。

3.网络字节序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节序采用big endian排序方式。字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序,一个字节的数据没有顺序的问题了。

小结:
主机序的顺序与CPU设计有关,数据的顺序是由cpu决定的,而网络序采用大端序。

二、主机序和网络序的转换

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

htons和ntohs完成16位无符号数的相互转换,htonl和ntohl完成32位无符号数的相互转换。
示例:

#include <arpa/inet.h>

unsigned int a = 0x12345678;
unsigned char *b = (unsigned char *)&a;
printf("host: %02x:%02x:%02x:%02x\n", b[0], b[1], b[2], b[3]);

a = htonl(a);
b = (unsigned char *)&a;
printf("network: %02x:%02x:%02x:%02x\n", b[0], b[1], b[2], b[3]);

host: 78:56:34:12
network: 12:34:56:78

三、socket字节序转换函数
1.常用函数说明

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

typedef uint32_t in_addr_t;
struct in_addr {
    in_addr_t s_addr;
};
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 */ 
}; 

#include <sys/socket.h>
struct sockaddr {  
	sa_family_t sin_family;//地址族
	char sa_data[14]; //14字节,包含套接字中的目标地址和端口信息               
}; 
//注:sockaddr的缺陷是:sa_data把目标地址和端口信息混在一起
//网络编程中我们会对sockaddr_in结构体进行操作,使用sockaddr_in来建立所需的信息,最后使用类型转化就可以了。
//一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数:sockaddr_in用于socket定义和赋值;sockaddr用于函数参数

//ipv4
in_addr_t inet_addr(const char *cp);
char *inet_ntoa(struct in_addr in);
int inet_aton(const char *cp, struct in_addr *inp);
//上面为常用的转换函数
in_addr_t inet_network(const char *cp);
struct in_addr inet_makeaddr(in_addr_t net, in_addr_t host);
in_addr_t inet_lnaof(struct in_addr in);
in_addr_t inet_netof(struct in_addr in);

//ipv6
//IPv4地址和IPv6地址都适用
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
//af 可以为AF_INET 或者 AF_INET6;
//inet_pton 函数表示由字符串src转为字节序dst;
//而inet_ntop表示由字节序src 转为字符串dst;
//inet_ntop 中size定义如下:
<netinet/in.h>
#define INET_ADDRSTRLEN 16  //ipv4
#define INET6_ADDRSTRLEN 46  //ipv6
//另外inet_ntop中dst参数不可以是一个空指针,调用者必须为其分配内存空间并指定大小,
//调用成功时该指针为该函数的返回值

示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
#if 1
    unsigned long l1,l2;
     char str[16];
    struct in_addr addr1, addr2;
    l1 = inet_addr("192.168.1.2");
    l2 = inet_addr("192.168.10.2");
    memcpy(&addr1, &l1, 4);
    memcpy(&addr2, &l2, 4);

    printf("%s : %s\n", inet_ntoa(addr1), inet_ntoa(addr2)); //注意
    printf("%s\n", inet_ntoa(addr1));
    printf("%s\n", inet_ntoa(addr2));

#endif
#if 1
    addr1.s_addr = inet_addr("192.168.100.2");
    inet_aton("192.168.100.100", &addr2);
    printf("%s\n", inet_ntoa(addr1));
    printf("%s\n", inet_ntoa(addr2));
#endif
#if 1
 	inet_pton(AF_INET, "192.168.22.21", &addr1.s_addr);
    inet_ntop(AF_INET, &addr1.s_addr, str,16);
    printf("%s\n", str);
#endif
	return 0;
}
192.168.1.2 : 192.168.1.2
192.168.1.2
192.168.10.2
192.168.100.2
192.168.100.100
192.168.22.21

注:
inet_ntoa返回一个char *,而这个char *的空间是在inet_ntoa里面静态分配的,所以inet_ntoa后面的调用会覆盖上一次的调用。再加上printf里面的可变参数的求值是从右到左的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值