|
学习要点:
1、认识ip地址,端口号,网络字节序等网络编程中的基本概念
2、学习socket api的基本用法
3、能够实现一个简单的udp客户端/服务器
4、能够实现一个简单的tcp客户端/服务器(单链接版本,多进程版本,多线程版本)
5、理解tcp服务器建立连接,发送数据,断开连接的流程。
理解源IP地址和目的IP地址:
在IP数据包头部中,有两个IP地址,分别叫做源IP地址,和目的IP地址
IP地址(公网IP)唯一的标识互联网中的一台主机
源IP,目的IP:对一个报文来讲,从哪来,到那里去。
最大的意义:指导一个报文,该如何进行路径选择到那里去。本质就是让我们根据目标,就行路径选择的依据。
数据刚开始的时候,是从哪里产生的呢? 计算机本身不产生数据,产生数据的是人,人通过特定的客户端产生数据。
本质上,所有的网络通信,站在普通人的角度,就是人和人之间通信。(小白)
技术人员的角度,所有的网络通信,本质是:进程间通信。
认识端口:
端口号(port)是传输层协议的内容
端口号是一个2字节16位的整数
端口号用来表示一个进程,告诉操作系统,当前的这个数据要交给哪一个进程来处理
IP地址+端口号能够标识网络上的某一台主机的某一个进程
整个网络看作是一个大的OS,所有的网络上网行为,基本上都是在这一个大的OS中,进行进程间通
理解端口号和进程ID:
端口号:唯一的标识一台机器上的唯一的一个进程!!
IP+PORT=能够标识互联网中的唯一一个进程
P地址+PORT端口号=socket
一个端口号只能被一个进程占用
要进行通信,本质:
1、先找到目标主机
2、在找到该主机上的服务(进程)
程具有独立性,进程间通信的前提工作:先要让不同的进程,看到同一份资源
一个进程可以关联多个端口号吗? 可以的
一个端口号可以关联多个进程吗? 不能
认识TCP协议:
传输层协议
有连接
可靠传输
面向字节流
认识UDP协议:
传输层协议
无连接
不可靠传输
面向数据报
TCP可靠,UDP不可靠,可靠不可靠是中性词,根据自己的需求和场景来选择TCP传输还是UDP传输
网络字节序:
内存中的多字节数据相对于内存地址有大小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大小端之分,网络数据同样有
发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出
接收主机吧从网络上街道的字节依次保存在接受缓冲区中,也是按内存地址从低到高的顺序保存
网络数据流的地址应这样规定,先发出的数据是低地址,后发出的数据是高地址
TCP/IP协议规定,网络数据流应采用大端字节序,即地址高字节
不管这台主机是大端机,还是小端机,都会按照这个TCP/IP规定的网络字节序来发送/接收数据
如果当前发送主机是小端,就需要先将数据转成大端,否则就忽略,直接发送即可
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换
#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)
h标识host,n标识network,l表示32位长整数,s表示16位短整数
htonl表示将32位的长整数从主机字节序转换为网络字节序
如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回
如果主机是大端字节序,这些函数不做转换,将参数原封不动的返回
socket编程接口:
网络通信的标准方式有很多种,基于ip的网络通信,AF_INET,原始套接字,域间套接字
socket常见API
// 创建socket文件描述符(TCP/UDP,客户端+服务器)
int socket(int domain , int type, int protocol)
// 绑定端口号(TCP/UDP,服务器)
int bind(int socket,const struct sockaddr *address,socklen_t address_len)
// 开始监听socket (TCP,服务器)
int listen(int socket,int backlog)
// 接受请求(TCP,服务器)
int accept(int socket,struct sockaddr* address,socklen_t* address_len);
// 建立连接(TCP,客户端)
int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体标识,包括16位地址类型,16位端口号和32位IP地址
socket API可以都用struct sockaddr *类标识,在使用的时候需要强制转化成sockaddr_in;这样的好处是程序的通用性。可以接收IPv4,IPv6,以及UNIX Domain Socket各种类型的sockaddr结构体指针作为参数
sockaddr结构
struct scokaddr
{
_SOCKADDR_COMMON(sa_);
char sa_data[14];
}
sockaddr_in结构
struct sockaddr_in
{
_SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number */
struct in_addr sin_addr;
usigned char sin_zero[sizeof (struct sockaddr) -
_SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
}
虽然socket api的接口是sockaddr,但是我们真正在基于IPv4编程是,使用的数据结构是sockaddr_in;这个结构里主要有三部分信息:地址类型,端口号,IP地址
in_addr结构
tpedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
}
in_addr用来表示一个IPv4的IP地址,其实就是一个32位的整数
简单的UDP网络程序
装UdpSocket
udp_socket.hpp |
|