1.网络编程的知识:
2.
3.
4.
5.TCP/IP协议
下面我们来简要了解TCP/IP的四层模型:
网络接口层:负责将二进制流转换为数据帧,并进行数据帧的发送和接收。数据帧是网络信息传输的基本单元,ARP和RARP协议。
网络层:负责将数据帧封装成IP数据报,同时负责选择数据报的路径,即路由,IP和ICMP协议。
传输层:负责端到端之间的通信会话连接与建立,传输协议的选择根据数据传输方式而定,UDP和TCP协议。
应用层:负责应用程序的网络访问,这里通过端口号来识别各个不同的进程,FTP、TELNET、DNS、SMTP、POP3 协议。
6.
7.
8.
9.TCP协议特点
1.TCP(即传输控制协议):是一种面向连接的传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信)
2.适用情况: 适合于对传输质量要求较高,以及传输大量数据的通信。
在需要可靠数据传输的场合,通常使用TCP协议
MSN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议
10.TCP/IP网络编程预备知识
Socket:一种不同主机间通信的文件
IP地址:标记不同主机
端口号:标记不同应用程序
字节序:传输规则
11.Socket 简介
Socket 是一个编程接口
是一种特殊的文件描述符 (everything in Unix is a file)
并不仅限于TCP/IP协议
面向连接 (Transmission Control Protocol - TCP/IP)
无连接 (User Datagram Protocol -UDP 和 Inter-network Packet Exchange - IPX)
12.Socket类型
流式套接字(SOCK_STREAM)
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。
数据报套接字(SOCK_DGRAM)
提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。
原始套接字(SOCK_RAW)
可以对较低层次协议如IP、ICMP直接访问。
13.IP地址
IP地址是Internet中主机的标识 Internet中的主机要与别的机器通信必须具有一个IP地址
IP地址为32位(IPv4)或者128位(IPv6) 每个数据包都必须携带目的IP地址和源IP地址,路由器依靠此信息为数据包选择路由。
表示形式:常用十进制点分形式,如202.38.64.10,最后都会转换为一个32位的无符号整数。
14.IP地址的转换(函数)
htonl( );主机字节序数值 转换为 网络字节序数值
ntohl();网络字节序数字 转化为 主机字节序数字
inet_aton() 将strptr所指的字符串转换成32位的网络字节序二进制值的数字
inet_addr() 函数 主机字节序的字符串 转换为 网络字节序的数值
inet_ntoa 将32位网络字节序二进制地址 转换成点分十进制的字符串。
inet_pton() 函数 主机字节序的字符串 转换为 网络字节序的数值
inet_ntop() 函数 网络字节序的数值 转换为 主机字节序的字符串
15.代码:
htonl( );主机字节序数值 转换为 网络字节序数值
ntohl();网络字节序数字 转化为 主机字节序数字
/************************************************************************************************************************************************************************************************************************
*文件名:
*作 者:She001
*时 间:
*版 本:
*作 用:主机字节序 转 网络字节序
网路字节序 转 主机字节序
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/msg.h>
#include<arpa/inet.h>
// host -- to -- network -- l : int s: short
// htonl
int main(int argc,char *argv[])
{
//主机字节序 转换为 网络字节序
int num =0x01020304;
int net_order = htonl(num);
printf("net_order = %#x\n",net_order);
//网络字节序 转化为 主机字节序
// network -- to -- host l :int
int host_order=ntohl(net_order);
printf("host_order=%#x\n",host_order);
return 0;
}
16.代码:
inet_aton() 将strptr所指的字符串转换成32位的网络字节序二进制值的数字
inet_ntoa 将32位网络字节序二进制地址 转换成点分十进制的字符串。
/************************************************************************************************************************************************************************************************************************
*文件名:
*作 者:She001
*时 间:
*版 本:
*作 用:
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
//主机字节序 : 1. 整数/数值 2.字符串
//网络字节序 : 数值
//主机 ip 地址 (十进制点分形式 字符串)
//主机字符串 转换为 网络字节序数值函数 inet_aton()
//反过来 inet_ntoa() 数字转换为字符串
int main(int argc,char *argv[])
{
//主机字节序 的字符串转换为 网络字节序的数字
char *ip="192.168.1.101";
struct in_addr res ={0};
int flg =inet_aton(ip,&res);//转换成功返回1
printf("flg =%d res = %#x\n",flg,res.s_addr);
// 网络字节序数字 转化为 主机字符串
printf("host is %s\n",inet_ntoa(res));
return 0;
}
17.代码:
inet_addr() 函数 主机字节序的字符串 转换为 网络字节序的数值
inet_pton() 函数 主机字节序的字符串 转换为 网络字节序的数值
inet_ntop() 函数 网络字节序的数值 转换为 主机字节序的字符串
/************************************************************************************************************************************************************************************************************************
*文件名:
*作 者:She001
*时 间:
*版 本:
*作 用:函数 inet_pton 函数
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
//
//1.inet_pton() 函数 主机字节序的字符串 转换为 网络字节序的数值
//2.inet_ntop() 函数 网络字节序的数值 转换为 主机字节序的字符串
//3.inet_addr() 函数 主机字节序的字符串 转换为 网络字节序的数值
//
//第一个的
//原型: int inet_pton(int af,const char*stc,void *det);
//参数: af: AF_ INET IPV4
// stc 要转化的字符串
// det 转换的结果,整形变量的地址
//返回值 : 成功 1 不成功: -1 没有转换的数据 0
//
//第三个
//原型: in_addr_t inet_addr(const char *cp);
//参数 ;cp :十进制点分形式的ip字符串
//返回值:网络字节序
//
//
//第二个
//原型: const char *inet_ntop(int af ,const void src,char *dsr socklen_t size)
//参数: af AF_IENT
// src 要转化的网络字符串
// dsr : 转化完的字符串
// size dsr的空间大小
//返回值:转换完的字符串
//
int main(int argc,char *argv[])
{
char *str="192.168.1.101";
unsigned int net_order=0;
//1.inet_pton() 函数 主机字节序的字符串 转换为 网络字节序的数值
int res =inet_pton(AF_INET,str,&net_order);
if(res <0)
{
perror("inet_pton error\n");
return -1;
}
printf("res =%d inet_pton= %u\n",res,net_order);
//3.inet_addr() 函数 主机字节序的字符串 转换为 网络字节序的数值
in_addr_t netorder1 = inet_addr(str);
printf("netorder = %u\n",netorder1);
//2.inet_ntop() 函数 网络字节序的数值 转换为 主机字节序的字符串
char ip[20]="";
const char* ipstr = inet_ntop(AF_INET,&net_order,ip,sizeof(ip));
printf("host ip = %s\n",ip);
printf("ipstr =%s \n",ipstr);
return 0;
}
18.测试代码 :测试大端(网络字节序) 小端 (主机字节序)的存储方式的不同
代码:
/************************************************************************************************************************************************************************************************************************
*文件名:
*作 者:She001
*时 间:
*版 本:
*作 用:网络编程
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/msg.h>
//查看数据在内存中的存储
//网络字节序 是大端存储的字节序, 是在两个电脑传输的时候用的东西
//主机字节序 是小端存储的字节序 是在自己的一个电脑上传输数据的东西
int main(int argc,char *argv[])
{
int num =0x01020304; //主机字节序 数据的存储 也叫小端存储
char *p=(char *)# //p 指向低地址
int i;
//真理 验证
for(i=0;i<4;i++)
{
printf("%p %#x\n",p,*p); //%#x 十六进制的输出
p++;
}
return 0;
}
19.端口号
为了区分一台主机接收到的数据包应该转交给哪个进程来进行处理,使用端口号来区别
TCP端口号与UDP端口号独立
端口号一般由IANA (Internet Assigned Numbers Authority) 管理 众所周知端口:1~1023(1~255之间为众所周知端口,256~1023端口通常由UNIX系统占用)
已登记端口:1024~49151
动态或私有端口:49152~65535
20.
21.字节序
不同类型CPU的主机中,内存存储多字节整数序列有两种方法,称为主机字节序(HBO): 小端序(little-endian) - 低序字节存储在低地址 将低字节存储在起始地址,称为“Little-Endian”字节序,Intel、AMD等采用的是这种方式; 大端序(big-endian)- 高序字节存储在低地址 将高字节存储在起始地址,称为“Big-Endian”字节序,由ARM、Motorola等所采用
网络中传输的数据必须按网络字节序,即大端字节序
在大部分PC机上,当应用进程将整数送入socket前,需要转化成网络字节序;当应用进程从socket取出整数后,要转化成小端字节序)
网络字节序(NBO - Network Byte Order) 使用统一的字节顺序,避免兼容性问题
主机字节序(HBO - Host Byte Order) 不同的机器HBO是不一样的,这与CPU的设计有关 Motorola 68K系列、ARM系列,HBO与NBO是一致的 Intel X86系列,HBO与NBO不一致
22.TCP/IP协议建立TCP连接的过程(三次握手)
A→B:主机A向主机B发送连接请求,报文中包括SYN控制标志,但没有数据。主机B收到SYN后,将其状态转化成SYN-RECEIVED
A←B:主机B向主机A发送建立连接请求,并会带队主机A的SYN确认。主机A收到消息后,将其状态变成ESTABLISHED
A→B:主机B收到主机A发来确认信息后,也将自身状态转化为ESTABLISHED,至此,一条TCP连接建立完毕。接下来就可以再两台主机间传输数据了
//建立连接-传输数据。
23.TCP/IP协议建立TCP关闭的过程 (四次挥手)
关闭TCP连接 发起连接的一方(主机A)
请求关闭TCP连接 主机B主动请求关闭TCP连接
主机A和主机B同时发起断开连接的请求。
24.打包 与 解包 的过程
代码:
/************************************************************************************************************************************************************************************************************************
*文件名:
*作 者:She001
*时 间:
*版 本:
*作 用:socket 编程接口 是一种特殊的文件描述符号,并不限于TCP/IP 协议
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
//struct sockaddr_in
//1.
//通用的网络编程接口: socket 位于会话层 和传输层 之间
//三种套接字 的类型
//SOCK_STREAM 流式套接字 TCP
// 数据报的套接字 UTP
// _sockaddr_in
int main(int argc,char *argv[])
{
if(argc <3)//参数判断
{
perror("argc error\n");
return -1;
}
//打包
//----------------------------
struct sockaddr_in saddr ={0};
saddr.sin_family=AF_INET; //IPV4 协议族
saddr.sin_addr.s_addr = inet_addr(argv[1]);//主机字节序 转换 网络字节序
saddr.sin_port = htons(atoi(argv[2])); // 端口号 字符串转换为主机字节序的整形 再次转化为 网络字节序的数字
//解包
//-------------------------------
printf("sever port = %d\n",ntohs(saddr.sin_port));
char ip[20]="";
printf("server ip =%s \n",inet_ntop(AF_INET,&saddr.sin_addr.s_addr ,ip,sizeof(ip)));
return 0;
}
25.函数;
//1.gethostname: 获取本主机的名称
//2.gethostbyname: 通过域名www.baidu.com 获得主机名
//3.sethostname 设置主机名
代码:
/************************************************************************************************************************************************************************************************************************
*文件名:
*作 者:She001
*时 间:
*版 本:
*作 用:
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
//1.gethostname: 获取本主机的名称
//2.gethostbyname: 通过域名www.baidu.com 获得主机名
//3.sethostname 设置主机名
int main()
{
/*
char hostname1[100]="student-machine";
if(!sethostname(hostname1,strlen(hostname1))) //设置主机名字
{
printf("set host = %s \n ",hostname1);
}
else
{
perror("set host error\n");
return -2;
}
*/
char hostname[200]="";
if(!gethostname(hostname,sizeof(hostname))) //获取主机名字
{
printf("hostname = %s \n",hostname);
}
else
{
printf("gethostname error\n");
return -1;
}
//通过域名获取主机名字
char *str="www.baidu.com";
struct hostent *host = gethostbyname(str);
if(host ==NULL)
{
perror("gethostbyname error\n");
}
else
printf("host name is %s\n",host->h_name);
//输出别名
while(*host->h_aliases !=NULL) //-> . [] 成员运算符 优先级很强
{
printf("aliases =%s \n",*host->h_aliases);
host->h_aliases++; //二级指针可以移位置
}
//获取地址列表
char ip[100]="";
while(*host->h_addr_list!=NULL)
{
printf("list : %s \n",inet_ntop(AF_INET,*host->h_addr_list,ip,sizeof(ip)));
host->h_addr_list++;//二级指针可以移位置
}
return 0;
}