一、基础知识就是要知道OSI开放系统互联参考模型以及四层模型和五层模型7. 应用层作用为应用程序提供网络服务接口用户交互协议HTTP、HTTPS、FTP、TFTP、SMTP、POP3、DNS、Telnet、SNMP数据报文6. 表示层作用翻译、加密解密、编码解码、压缩解压解决两个主机数据格式不一样的问题确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。例子JPG、GIF 编码、SSL 加密、ASCII/EBCDIC 字符转换注意HTTPS 的 SSL/TLS 属于表示层功能5. 会话层作用建立、管理、断开会话连接同步、断点续传即通过传输层建立数据传输的通路例子登录验证、会话断点恢复4. 传输层作用端到端进程‑进程通信差错校验、流量控制、端口寻址定义传输数据的协议和端协议TCP可靠、面向连接、UDP不可靠、无连接设备网关、防火墙逻辑标识端口号数据单元段 Segment3. 网络层作用主机‑主机通信路由选择、IP 寻址、分组转发。传输数据包为位于不容位置的网络中的两个主机系统之间提供连接和路径选择就是将一个局域网和另一个局域网连接起来。协议IP、ARP、ICMP、IGMP、RIP、OSPF典型设备路由器、三层交换机数据单元分组数据包Packet2. 数据链路层作用帧封装即让格式化数据以帧为单位进行传输MAC 物理地址寻址差错检测重传相邻节点传输协议以太网 Ethernet、PPP ‑ 典型设备网卡、网桥、二层交换机数据单元帧 Frame1. 物理层作用传输原始比特流 0/1即以2进制传输光信号或电信号定义硬件电气、机械标准设备集线器 HUB、中继器、网线、光纤、RJ45 接口数据单元比特 Bit层级作用示例应用层给程序用的业务数据HTTP、API、JSON传输层负责两个程序之间可靠传输数据TCP / UDP网络层负责找到对方电脑 IP 地址IP 协议数据链路层局域网传输网卡、以太网物理层网线、无线电信号硬件反正就是都要记住二、TCP协议TCP(transmit control protocol):类似打电话是一种可靠传输。特点:a.面向连接就是在进行通信之前必须建立好一条逻辑上的通路b.提供可靠传输四个无无丢失无失序无差错无重复因为会对每个字节都进行编号所以出错的话就很容易找出来c.字节流有好处有问题1.建立连接的过程tcp通过三次握手来建立连接(客户端) (服务器)client --------------------------------- server1 --------- 我要通话拨号 -------2 ------喂服务器接听电话-----3 -------------------喂 -----------------这个过程其实就是相当于测试服务器能收到客户端的信息客户端能收到服务器的信息。2.tcp通信模型CS 模型 (Client Server 客户端服务器模型)BS 模型 (Browser Server 浏览器服务器模型)P2P模型 (Peer to Peer 点对点)3.一些小知识socket套接字是操作系统给你的 C 语言程序访问 TCP/UDP 通道的工具它不是网络层协议它是程序和操作系统网络模块之间的接口 API。类比TCP 是水管socket 就是你家水龙头你拧开水龙头 (socket)水流 (TCP 数据) 就能进出。API 指服务器对外开放、允许外部程序访问的功能入口。访问这个 API需要使用 HTTP 协议通过 TCP 传输。调用socket()拿到套接字 fd水龙头-connect(fd,服务器地址)三次握手建立 TCP 连接管道打通-send(fd,http报文)→ 通过已经建好的 TCP 管道发送 HTTP‑GET 请求去调用 API接收recv(fd,R_buf,...)→ TCP 管道把服务器返回的 JSON 数据传回你的程序-关闭套接字断开 TCP 连接。4.通信过程1socket 买个了手机bind 可选的一般不绑定2connect 拨打电话3read/write 说话4close 挂电话服务器端:1socket 买个了手机2bind 插了SIM卡 --- 绑定服务器地址信息3listen 待机 --- 监听是否有客户端连接4accept 接听电话 --- 处理客户端的连接 完成连接建立5read/write 说话6close 挂电话5.客户端具体函数1socket头文件#include sys/types.h #include sys/socket.h形式int socket(int domain, int type, int protocol);功能:创建通信的一端参数:domain有三种选择我们一边选择IPv4AF_UNIX, AF_LOCAL Local communicationAF_INET IPv4 Internet protocolsAF_INET6 IPv6 Internet protocolstype:SOCK_STREAM流式套接字提供双向有序可靠面向连接的字节流(其实就是TCP)SOCK_DGRAM数据报套接字提供无连接不可靠的数据报其实就是UDPprotocol:协议(tpc或udp)给 0 表示默认协议就是流式是TCP报文是UDP。返回值:成功时返回socket的文件描述符失败时返回-1并设置errno。2connectint connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);功能:发起连接请求参数:sockfd用到的socket的fdaddr要通信地址对于客户端来说就是服务器的地址(ip端口号)addrlen表示的式 addr 参数地址的大小返回值:成功时返回0失败时返回-1并设置errnoser_addr本来是struct sockaddr_in*前面加(struct sockaddr *)强制转换成 connect 要求的指针类型。struct sockaddr_in {sa_family_t sin_family; AF_INETIPV4in_port_t sin_port; 端口号struct in_addr sin_addr; ip地址};它就是嵌套在struct sockaddr_in里面专门存放 IPv4 IP 地址的子结构体struct in_addr {uint32_t s_addr; /* address in network byte order */};3将端口号 转换为网络字节序的端口号形式uint16_t htons(uint16_t hostshort);功能:将hostshort值转换为网络字节序返回4将ip地址转换为网络字节序的ip地址形式in_addr_t inet_addr(const char *cp);功能:将字符串形式ip地址cp(点分十进制) 转换为 网络字节序形式的IP地址返回5将结构体中的内容清空形式void bzero(void *s, size_t n);6.网络中的地址addr解决怎么在找到一台主机以及这台主机上进程1IP地址是网络中主机的唯一标识它由网络地址和主机号组成。网络地址是子网的唯一标识类似于电话号码的区号主机号是子网内每台主机的编号。ip的本质:在现在(IPv4)的网络中IP地址是32bit的二进制数采用大端字节序.2表示方法(点分十进制)直接使用二进制数不容易记忆为了方便记忆将32位二进制码划分为4个字节每个字节转化成相应的十进制数字节之间用“.”来分隔这种表示方法称之为“点分十进制表示法”。例192 .168 .1 .111000000 10101000 00000001 000000013Ip地址分类 (Ipv4)类别首字节十进制开头比特默认掩码A0‑1270255.0.0.0B128‑19110255.255.0.0C192‑223110255.255.255.0D224‑2391110无E240‑2551111无4子网掩码作用区分一个 IP 地址哪一部分是网络号哪一部分是主机号IPv4 地址 网络号 主机号在网络中找到一台主机用ip来找找到主机中进程用端口号来找那么ip号端口号能确定武罗中进程的唯一地址。端口号组成由16位的数据也就是0~65535组成1~1023是知名端口号80 http1024~50000是系统注册的因为不是所有网站都是知名网站50000是动态的我们写代码一般用这一部分。7.服务器端服务器端使用的socket和connect是一样的1int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);功能:给sockfd 绑定一个名字也就是地址信息参数:sockfd是要绑定的socketaddr是绑定服务器自己的地址addrlen是服务器地址大小返回值:成功时返回0失败时返回-1并设置errno2int listen(int sockfd, int backlog);功能:将sockfd设置为监听套接字(被动套接字)参数:sockfd为要设置的socketbacklog表示等待队列的大小他的大小决定他能监听几个套接字返回值成功时返回0失败返回-1并设置errno3int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);功能:从listen的等待队列中提取第一个连接请求完成连接同时创建一个socket 表示已经连接好的socket最终返回这个已连接好的socket的fd参数:sockfd时监听套接字的fdaddr是用来保存对端地址信息addrlen是值结果参数必须初始化sizeof(客户端地址类型)返回值:成功返回已经连接好的socket的fd失败时返回-1并errno被设置如果想知道客户端的地址信息:struct sockaddr_in cliaddr;socklen_t addrlen sizeof(cliaddr);accept(sockfd, ( struct sockaddr *)cliaddr, addrlen)char *inet_ntoa(struct in_addr in);功能:将网络字节序的ip地址in 转换为 字符串形式的ip地址 返回注意:客户端只有一个socket服务器有两个socket一个监听的socket一个通信的socket三、UDP协议UDP(User Datagram Protocol):(类似 生活中的广播)特点不提供可靠传输在数据发送时不需要建立连接1无连接2不保证可靠传输3数据报 --- 一包一包应用:(1).小数据但是对速度要求较高(QQ.及时文本信息语音等)实时性要求较高场合(2).广播组播 //电子教师(vnc --- 广播)(3).无线网的传输 //udp1.函数1发送ssize_t send (int sockfd, const void *buf, size_t len, int flags);ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);功能:sendto 将数据发送到指定的地址中通过sockfd参数:sockfd --- 表示socket对应的fdbuf --- 存放数据的一块内存空间len --- 表示要发送的字节数flags --- 发送的标志 MSG_DONWAIT //非阻塞 --- 不在等 0 ---默认方式dest_addr --- 目标地址 --- 代表要发送到的目的地址addrlen --- 代表 目标地址数据的长度 sizeof(dest_addr)返回值:成功 返回发送出去的字节数失败 -1 errno被设置2接收ssize_t recv (int sockfd, void *buf, size_t len, int flags);ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);功能:从socket中接收消息参数:sockfd --- 表示socket对应的fdbuf --- 存放数据的一块内存空间len --- 表示打算读取的字节数flags --- 读取的标志 MSG_DONWAIT //非阻塞 --- 不在等src_addr --- 表示数据的源地址addrlen --- 源地址大小 值结果参数socklen_t addrlen sizeof(src_addr);返回值:成功 返回读取到的字节数失败 -1 errno被设置例实现服务器和客户端相互收发1服务器#include stdio.h #include sys/types.h /* See NOTES */ #include sys/socket.h #include netinet/in.h #include netinet/ip.h /* superset of previous */ #include strings.h #include arpa/inet.h #include string.h #include unistd.h #include sys/wait.h #include signal.h #include stdlib.h #include errno.h #include pthread.h struct sockaddr_in srcaddr; void * do_send (void *arg) { int serfd *(int *)arg; char buf[1024]; while (1) { printf( ); fgets(buf,sizeof(buf),stdin); sendto(serfd,buf,strlen(buf)1,0,(const struct sockaddr *)srcaddr,sizeof(srcaddr)); if (strncmp(buf,quit,4) 0) { close(serfd); exit(0); } } return NULL; } void* do_recv(void *arg) { char buf[1024]; int serfd *(int *)arg; while (1) { recvfrom(serfd,buf,sizeof(buf),0,NULL,NULL); printf(buf %s\n,buf); if (strncmp(buf,quit,4) 0) { close(serfd); exit(0); } } return NULL; } int main(int argc, const char *argv[]) { int serfd socket(AF_INET,SOCK_DGRAM,0); if (serfd 0) { perror(socket fail); return -1; } //bind struct sockaddr_in seraddr; bzero(seraddr,sizeof(seraddr)); seraddr.sin_family AF_INET; seraddr.sin_addr.s_addr INADDR_ANY; seraddr.sin_port htons(50000); if (bind(serfd,(const struct sockaddr*)seraddr,sizeof(seraddr)) 0) { perror(bind fail); return -1; } //recvfrom 函数 socklen_t len sizeof(srcaddr); char buf[1024]; recvfrom(serfd,buf,sizeof(buf),0,(struct sockaddr*)srcaddr,len); printf(-------------------\n); printf(ip %s\n,inet_ntoa(srcaddr.sin_addr)); printf(port %d\n,ntohs(srcaddr.sin_port)); printf(-------------------\n); printf(buf %s\n,buf); pthread_t tid[2]; int ret pthread_create(tid[0],NULL,do_send,serfd); if (ret ! 0) { errno ret; perror(pthread_create fail); return -1; } pthread_detach(tid[0]); ret pthread_create(tid[1],NULL,do_recv,serfd); if (ret ! 0) { errno ret; perror(pthread_create fail); return -1; } pthread_detach(tid[1]); pthread_exit(NULL); return 0; }2客户端#include stdio.h #include sys/types.h #include sys/socket.h #include netinet/in.h #include netinet/ip.h #include strings.h #include string.h #include arpa/inet.h #include unistd.h #include signal.h #include stdlib.h #include sys/wait.h #include errno.h #include pthread.h struct sockaddr_in seraddr; void * do_send (void *arg) { int clifd *(int *)arg; char buf[1024]; while (1) { printf( ); fgets(buf,sizeof(buf),stdin); sendto(clifd,buf,strlen(buf)1,0,(const struct sockaddr *)seraddr,sizeof(seraddr)); if (strncmp(buf,quit,4) 0) { close(clifd); exit(0); } } return NULL; } void* do_recv(void *arg) { char buf[1024]; int clifd *(int *)arg; while (1) { recvfrom(clifd,buf,sizeof(buf),0,NULL,NULL); printf(buf %s\n,buf); if (strncmp(buf,quit,4) 0) { close(clifd); exit(0); } } return NULL; } int main(int argc, const char *argv[]) { int clifd socket(AF_INET,SOCK_DGRAM,0); if (clifd 0) { perror(socket fail); return -1; } char buf[1024] udp!\n; bzero(seraddr,sizeof(seraddr)); seraddr.sin_family AF_INET; seraddr.sin_addr.s_addr inet_addr(127.0.0.1); seraddr.sin_port htons(50000); sendto(clifd,buf,strlen(buf)1,0,(const struct sockaddr *)seraddr,sizeof(seraddr)); pthread_t tid[2]; int ret pthread_create(tid[0],NULL,do_send,clifd); if (ret ! 0) { errno ret; perror(pthread_create fail); return -1; } pthread_detach(tid[0]); ret pthread_create(tid[1],NULL,do_recv,clifd); if (ret ! 0) { errno ret; perror(pthread_create fail); return -1; } pthread_detach(tid[1]); pthread_exit(NULL); return 0; }