网络编程相关概念

socket 提供可通信的场所

ip地址 确定唯一的主机

端口号 确定唯一的进程

字节序 数据能够看懂

1. socket 套接字

1982 - Berkeley Software Distributions 操作系统引入了socket作为本地进程之间通信的接口

1986 - Berkeley 扩展了socket 接口,使之支持UNIX 下的TCP/IP 通信

现在很多应用 (FTP, Telnet, etc) 都依赖这一接口

是一个函数接口,会返回文件描述符

不管是TCP还是UDP都要使用它

socket的类型:

流式套接字(SOCK_STREAM)

提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。

用于TCP

数据报套接字(SOCK_DGRAM)

提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。

用于UDP

原始套接字(SOCK_RAW)

可以对较低层次协议如IP、ICMP直接访问。

2. ip地址

ip地址是在网络中确定唯一一台主机

mac地址是在一个局域网内确定唯一一台主机,每一个网卡在出厂是会分配一个编号,这个编号就称之为mac地址,每一个mac地址占6字节

查询ip地址的命令:

linux: ifconfig

windows: ipconfig

ip地址的分类:

IPV4,占32位,4个字节

IPV6,占128位,16个字节

IPV4地址的表示形式:

点分十进制,例如192.168.50.216,三个点将地址等分成四个部分,每个部分1个字节,每一部分范围都是0-255

注意:点分十进制的形式只是人为了方便识别才这样写的,开发时只需要将32为地址设置即可,不能加点

点分十进制的ip地址本质是一个字符串,32位的ip地址本质是一个无符号的int类型的整形数据

I

PV4地址的分类(基于ipv4地址前八位来分的)

A类 0000 0000 - 0111 1111 0.x.x.x - 127.x.x.x

B类 1000 0000 - 1011 1111 128.x.x.x - 191.x.x.x

C类 1100 0000 - 1101 1111 192.x.x.x - 223.x.x.x

D类 1110 0000 - 1110 1111 224.x.x.x - 239.x.x.x

E类 1111 0000 - 1111 1111 240.x.x.x - 255.x.x.x

特殊的ip地址:

D类ip地址都是组播地址

E类ip地址属于保留测试

127.x.x.x 属于每一台主机的本地地址,主要用于一台主机的多个进程通过套接字通信可以使用这个ip地址

局域网地址:任意一个ip地址都可以通过路由器下分局域网ip地址,为了解决ipv4地址不够用的问题

ipv4的C类地址的前24为称为网络号,后8位称为主机号

任意一个网段的ip地址中也有一些特殊的ip地址:

拿192.168.50网段举例

192.168.50.0 表示网络号,或者网段

192.168.50.255 表示当前网段下的广播地址

192.168.50.1 表示网关,是路由器的ip地址

理论上一个网段最后可以分配256个ip地址,但是实际只能连接254个

子网掩码:用于判断一个网段下能够连接主机的个数

子网掩码也是32位,每一位与ipv4的地址对应,子网掩码一般是由连续个1和连续个0组成,连续个1对应的ip地址的对应位置称之为网络号,连续个0对应的ip地址的对应位置称之为主机号,所以理论上有多少个0就可以判断连接的主机数

A类ip地址的子网掩码为 255.0.0.0

B类ip地址的子网掩码为 255.255.0.0

C类ip地址的子网掩码为 255.255.255.0

练习题:192.168.50网段下的子网掩码是255.255.255.128,

请问实际连接的主机数是 2^7 - 2 = 126 ,

范围是 192.168.50.129 - 192.168.50.254

地址转换函数:

主要指点分十进制ip地址和无符号32为int类型的ip地址之间的转换

这个转化过程不需要自己实现,有专门的函数已经实现好了:inet_addr inet_ntoa

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//将点分十进制ip地址转化为无符号32位整形数据
in_addr_t inet_addr(const char *cp);

//将无符号32位整形数据转化为点分十进制ip地址
char *inet_ntoa(struct in_addr in);

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

int main(int argc, char const *argv[])
{
    char ip_str[] = "192.168.50.216";
    unsigned int ip_int;

    ip_int = inet_addr(ip_str);

    printf("ip_str = %s\n", ip_str);
    printf("ip_int = %u\n", ip_int);
    printf("ip_int = %#x\n", ip_int);

    unsigned char *p = (unsigned char *)&ip_int;
    printf("%d.%d.%d.%d\n", *p, *(p+1), *(p+2), *(p+3));

    return 0;
}

3. 端口号

端口号是人为设置的用来区分一个操作系统中进程的编号,一个端口号标识一台主机的唯一一个进程

端口号一般由IANA (Internet Assigned Numbers Authority) 管理

众所周知端口:1~1023(1~255之间为众所周知端口,256~1023端口通常由UNIX系统占用)

已登记端口:1024~49151

动态或私有端口:49152~65535

可以使用vi /etc/services 查看已经被占用的端口号,一般我们可以使用6666、7777、8888、9999、10000、10001都可以用

4. 字节序

不同类型CPU的主机中,内存存储多字节整数序列有两种方法,称为主机字节序(HBO):

小端序(little-endian) - 低序字节存储在低地址

将低字节存储在起始地址,称为“Little-Endian”字节序,Intel、AMD等采用的是这种方式;

大端序(big-endian)- 高序字节存储在低地址

将高字节存储在起始地址,称为“Big-Endian”字节序,由ARM、Motorola等所采用

如何测试主机字节序:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int a = 0x12345678;

    char *p = (char *)&a;

    printf("*p = %#x\n", *p);

    if(*p == 0x78)
    {
        printf("小端存储\n");
    }
    else 
    {
        printf("大端存储\n");
    }

    return 0;
}

如果两个主机之间想要通信,那么还需要确定两个主机的字节序是否一样,如果不一样,收发的数据可以会出问题

网络中传输的数据必须按网络字节序,即大端字节序

例如:张三要给李四发送数据,张三就需要将数据从主机字节序转化为网络字节序,李四接收到数据之后,将网络字节序的数据转化为主机字节序,这样就保证数据传输无误

什么样的数据在传输的时候需要考虑字节序?

如果是单个字符或者字符串,是不需要考虑字节序的,因为一个字节一个字节存取时不涉及字节序的转换

如果多个字节作为一个整体,就需要考虑字节序,比如端口号

具体主机字节序与网络字节序之间的转换不需要自己实现,有专门的函数

htons htonl ntohs ntohl

#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);

#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char const *argv[])
{
    unsigned int a = 0x12345678;

    unsigned int b = htonl(a);

    printf("a = %#x\n", a);
    printf("b = %#x\n", b);

    return 0;
}

执行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小徐的记事本

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值