嵌入式Linux网络编程

2019-07-12 18:11发布

计算机网络基础

OSI参考模型及ISO参考模型

OSI 七层模型(理想模型)
应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 TCP/IP 四层模型(广泛应用)
应用层 传输层 网络层(Internet) 网络接口层(HW / 网卡)
对应关系
这里写图片描述
这里写图片描述 TCP/IP模型各层对应的协议
应用层协议:http ftp telnet 传输层协议(端口号工作在该层):TCP UDP TCP 传输控制协议: 可靠协议, 建立在连接上(打电话),要求通信过程中有回应,才能说下一句话。 TCP占用网络资源更多,用在使用账户密码登录或者是对数据完整性有要求的时候 UDP 用户数据报协议: 不可靠协议, 不需要建立连接(发短信、写信) 看视频、QQ等聊天等对数据的及时性和完整性没有要求 如果TCP和UDP都能使用的场合,网络越差越应该使用UDP port 端口号: (识别到底是哪个应用程序)源&目标 16位-- 2Byte short型 端口号一般由IANA管理 众所周知端口:1~1023(1~255之间为众所周知端口,256~1023端口通常由UNIX系统占用) 如:ftp– 21,telnet-23,http(web)-80 动态或者私有端口 49151— 65535
注册端口 1024–49150 网络层: IPv4 IPv6 ICMP IGMP (IP) 网络接口层: ARP RARP MPLS

IP地址的划分

这里写图片描述 A 最高位为0, 只有最高字节表示网络,剩下字节表示主机 网络个数 0~ 0x7f 主机个数 0~0xffffff 0.0.0.0 表示本网络 127(即01111111)保留作为本机软件回路测试之用 地址范围 0.0.0.1~~~~ 126.255.255.255 对应的掩码(网络的字节数)255.0.0.0 B 最高位为10,最高两个字节表示网络,剩下字节表示主机 网络个数 0~ 0x3fff 主机个数 0~0xffff 地址范围 128.0.0.0 ~ 191.255.255.255 对应的掩码(网络的字节数)255.255.0.0 C 最高位为110,最高三个字节表示网络,剩下字节表示主机 网络个数 0~ 0x1fffff 主机个数 0~0xff 地址范围 192.0.0.0 ~ 223.255.255.255 对应的掩码(网络的字节数)255.255.255.0 (192.168.1.2 255.255.255.0都是判断依据) D multicast 组播 二进制表示 11100000 00000000 00000000 00000000 ~ 11101111 11111111 11111111 11111111 转成十六进制 224.0.0.0 ~~ 239.255.255.255 另外还有broadcast 广播地址,最后一个字节为255

网络字节序(大端)

字符串与网络字节序的转换(转换IP)

  • inet_aton
  • inet_ntoa
  • inet_addr int inet_aton(const char *cp, struct in_addr *inp); 转换网络主机地址cp为二进制数值,并存储在struct in_addr结构中,即第二个参数*inp,函数返回非0表示cp主机有地有效,返回0 表示主机地址无效。 char *inet_ntoa(struct in_addr in); 函数转换网络字节排序的地址为标准的ASCII以点分开的地址,,该函数返回指向点分开的字符串地址的指针,**该字符串的空间为静态分配的**, 这意味着在第二次调用该函数时,上一次调用将会被重写(复盖),所以如果需要保存该串最后复制出来自己管理! in_addr_t inet_addr(const char *cp); 该函数转换网络主机地址(如192.168.1.10)为网络字节序二进制值,如果参数char *cp无效,函数返回-1(INADDR_NONE), 这个函数在处理地址为255.255.255.255时也返回-1,255.255.255.255是一个有效的地址,不过inet_addr无法处理;

主机字节序与网络字节序的转换(转换端口号)

  • htons (short针对两个字节的转换 )
  • htonl (long 针对四个字节的转换)
  • ntohs (short针对两个字节的转换)
  • ntohl (long 针对四个字节的转换)

socket套接字

TCP协议C-S模型

TCP协议的流程图

UDP协议C-S模型

这里写图片描述

TUP/UDP函数实现

1、socket()函数 int socket(int domain, int type, int protocol); domain 选择地址类型 IPv4 AF_INET IPv6 AF_INET6 type SOCKET 类型 TCP SOCK_STREAM UDP SOCK_DGRAM protocol 一般为0 除非是用原始SOCKET TCP:sockfd = socket(AF_INET,SOCK_STREAM,0); UDP:sockfd =socket(AF_INET, SOCK_DGRAM,0); 2、bind()函数—将本地IP地址绑定到端口号 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 因为该结构体中的sa_data成员不知如何赋值 struct sockaddr { sa_family_t sa_family; char sa_data[14]; } 所以使用同长结构体 struct sockaddr_in //(注意网络字节序需要转换) { short int sin_family ;//地址族 unsigned short int sin_port ; 端口号 // 2 (别人如何找到我) struct in_addr sin_addr; IP地址 // 如果是0.0.0.0(INADDR_ANY)表示本机IP // 4 struct in_addr { in_addr_t s_addr;}; 是个32位无符号int , 大端 unsigned char sin_zero[8]; } 3、listen()、connect()函数 int listen(int sockfd, int backlog); int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。 connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。 4、accept()函数 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。
5、send ()、recv ()等函数
  • send 往本进程的通信socket发送数据
  • recv 从本进程的通信socket接收数据
#include ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags); ssize_t send(int sockfd, const void *buff, size_t nbytes, int flags); 6、close()函数—关闭socket 结束通信 #include int close(int fd);