一、网络基本概要
1、网络通信概念:
不同主机的进程间通信
2、IP地址:
- 概念:类似于就是网络中身份证 ---- 用来唯一的标识一台主机 ,由网络地址和主机号组成
- 便于记忆,利用点分十进制表示法(类似于192.168.1.1)
- 主机号为0的IP地址是网络地址,主机号为255的地址是广播地址



3、子网掩码:
- 概念:用来区分IP地址中的网络地址和主机地址,搭配IP地址使用
- 子网掩码1:对应IP地址的网络位
- 子网掩码0:对应IP地址的主机位

4、端口号:
- 概念:16位的数值0-65535
- 作用:唯一的标识一个进程,每一个应用的进程都有一个端口号,通讯时用来区分数据包属于哪个进程
- 分类
- 任何TCP/IP实现所提供的服务都用1-1023之间的端口号:
- http:80 FTP:20/2 HTTPS: 443 TFPT: 69
- 端口号从1024-49151是被注册的端口号,被IANA指定为特殊服务使用
- 从49152-65535是动态或私有端口号
- 所以代码调试时,常使用端口号50000的
- 任何TCP/IP实现所提供的服务都用1-1023之间的端口号:
5、网络配置:
- ping IP地址/域名
- eg: ping www.baidu.com
- ifconfig 查看当前操作系统中网卡信息
- ens33:虚拟机中的网卡
- lo:回环地址(127.0.0.1)
- inet:IPv4地址
- netmask:子网掩码
- broadcast:广播号
- inet6:IPv6地址
- ether:MAC地址
6、国际网络体系结构
- OSI模型: open system interconnect 理论模型
- 应用层:要传输的数据信息,如文件传输,电子邮件等
- 表示层:数据加密,解密操作,压缩,解压缩
- 会话层:建立数据传输通道
- 传输层:传输的方式 UDP TCP 端口
- 网络层:实现数据路由 路由器 ip
- 数据链路层:封装成帧,点对点通信(局域网内通信),差错检测 交换机 ARP
- 物理层:定义物理设备标准,比如网线,光纤等传输介质 比特流 bit 0 1
- TCP/IP模型: 工业模型 4层
- 应用层:HTTP、HTTPS、FTP、TFTP、MQTT
- 传输层:TCP、UDP
- 网络层:IP
- 网络接口层:网络接口层既是传输数据的物理媒介,也可以为网络层提供一条准确无误的线
- TCP模型:5层
- 应用层:HTTP、HTTPS、FTP、TFTP、MQTT
- 传输层:TCP、UDP
- 网络层:IP
- 数据链路层:封装成帧,点对点通信(局域网内通信),差错检测 交换机
- 物理层:定义物理设备标准,比如网线,光纤等传输介质 比特流 bit
- 应用层:HTTP、HTTPS、FTP、TFTP、MQTT

7、基本协议:
- 应用层协议:
- FTP:文件传输协议(实现文件上传/下载)
- TFTP:简单文件传输协议(实现文件上传/下载)
- HTTP:超文本传输协议(实现超文本(集视频、图片、文字于一体的文件类型)传输)
- HTTPS:加密版超文本传输协议
- MQTT:消息队列遥测传输协议(物联网传输)
- 传输层协议:
- UDP:用户数据报协议
- TCP:传输控制协议
8、TCP与UDP协议
- TCP(即传输控制协议)
- 特点:面向连接、可靠、字节流
- 注重于:可靠性、稳定性
- 实际应用:类似打电话
- 是一种面向连接的传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信)
- 适用情况:
- 适合于对传输质量要求较高,以及传输大量数据的通信。
- 在需要可靠数据传输的场合,通常使用TCP协议
- MSN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议
- UDP(用户数据报协议)
- 特点:无连接、不可靠、数据报
- 注重于:实时性、效率高
- 实际应用:早期监控(似直播,有服务器接收)想要稳定(会借鉴tcp的协议,稳定性)
- 可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。
- 适用情况:
- 发送小尺寸数据(如对DNS服务器进行IP地址查询时)
- 在接收到数据,给出应答较困难的网络中使用UDP。(如:无
线网络) - 适合于广播/组播式通信中。
- MSN/QQ/Skype等即时通讯软件的点对点文本通讯以及音视频通
讯通常采用UDP协议 - 流媒体、VOD、VoIP、IPTV等网络多媒体服务中通常采用UDP
方式进行实时数据传输
二、函数接口
1、socket
原型:
int socket(int domain, int type, int protocol);
头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>功能:
创建一个套接字文件(用来通信的接口(文件描述符))
参数:
- domain:协议族/地址族(address family)
- 常用[AF_INET]、[AF_INET6]
- typ:数据传输方式
- 常用[SOCK_STREAM]、[SOCK_DGRAM]
- protocol:协议
- 通常为0,表示让系统自动选择最匹配的协议
返回值:
成功:返回socket对应的文件描述符(fd)
失败:返回-1
IPv4地址形式:
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
2、send
类似于write
函数原型:ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
功能: 向socket中发送信息
参数: sockfd:要操作的socket
buf :存放数据的空间
len :buf的大小
flags :指定读取信息的操作标志-MSG_DONTWAI
返回值:
成功返回实际发送字节数
失败返回-1
3、sendto
函数原型:ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
功能:
向一个IP地址和端口发送数据信息
端口号:区分一台主机不同的应用程序(0 - 65535)
参数:
sockfd:套接字文件描述符
buf:发送数据空间首地址
len:发送数据的长度
flags:发送数据属性(默认为0)
dest_addr:目的IP地址和端口
addrlen:目的IP地址和端口的长度
返回值:
成功返回实际发送字节数
失败返回-1
4、recv
类似于read
函数原型:ssize_t recv(int sockfd, void *buf, size_t len , int flags);
功能: 从socket中接收信息
参数: sockfd:要操作的socket
buf :存放数据的空间
len :buf的大小
flags :指定读取信息的操作标志-MSG_DONTWAI
返回值: 成功 读取到的字节数
失败-1
5、recvfrom
函数原型: ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
功能: 接收网络发送的数据信息
参数: sockfd:套接字文件描述符
buf:发送数据空间首地址
len:最大能够接收的数据个数
flags:属性默认为0
src_addr:存放发送端IP地址信息的空间首地址
addrlen:想要接收的数据长度的空间首地址
返回值: 成功返回实际接收字节数
失败返回-1
具有阻塞功能(直到接收到数据,才会继续向下执行)
4、htons主机转网络字节序
- 主机:小端或者大端 ----host
- 网络:统一大端 ----network
- 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:net、l:long、s:short
5、inet_addr与inet_ntoa
函数原型: in_addr_t inet_addr(const char *cp);
功能: 将字符串IP地址转换成二进制IP地址形式
cp 表示要用的ip地址的字符串 //点分十进制
函数原型: char *inet_ntoa(struct in_addr in);
功能: 将二进制ip转换成字符串
5、bind
函数原型: int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能: 将一个套接字与IP地址和端口号绑定(只能绑定自己的IP地址)
参数: sockfd:套接字文件描述符
addr:IP地址和端口号结构体首地址
addrlen:长度
返回值: 成功返回0
失败返回-1
7、accept
函数原型: int accept (int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能: 从监听的socket中提取连接请求,完成连接(三次握手)
返回已连接的一个新socket
参数: sockfd:监听的socket的fd
addr :用来存放,客户端的地址信息
addrlen : 值结果参数
返回值: 成功返回 已连接的socket的fd //专门用于后面通信的
失败-1
注意: addrlen必须初始化 ,初始成 addr对应sockaddr_in 类型的大小
8、tcp客户端
socket
connect
9、tcp服务器
socket
bind
listen
connfd = accept()
练习
1、客户端实现收发功能(配合网络调试助手完成)
#include "../head.h"
int main(int arg,char const *argv[]) //主函数传参
{
char tmp[256] = {"hello world"};int fd = socket(AF_INET,SOCK_STREAM,0);
if (fd < 0)
{
perror("fail to socket");
return -1;
}
printf("fd = %d\n",fd);struct sockaddr_in seraddr;
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(50000);
seraddr.sin_addr.s_addr = inet_addr("192.168.0.161");if (connect(fd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0)
{
perror("fail to connect");
return -1;
}while (1)
{
fgets(tmp,sizeof(tmp),stdin);
tmp[strlen(tmp)-1] = '\0';
if (0 == strcmp(tmp,".quit"))
{
break;
}
write(fd,tmp,strlen(tmp)+1);}
close(fd);
return 0;
}
2、服务器实现实现收发功能(配合网络调试助手完成)
#include "../head.h"
int main(int argc,char const*argv[])
{
int fd = 0;fd = socket(AF_INET,SOCK_STREAM,0);
if (fd < 0)
{
perror("fail to socket");
return -1;
}
printf("fd = %d\n",fd);
struct sockaddr_in seraddr;
bzero(&seraddr,sizeof(seraddr)); //初始化
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(50000);
seraddr.sin_addr.s_addr = inet_addr("192.168.0.162");
if (bind(fd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0)
{
perror("fail to bind");
return -1;
}if (listen(fd,5) < 0)
{
perror("fail to listen");
return -1;
}
#if 0int connfd = accept(fd,NULL,NULL);
if (connfd < 0 )
{
perror("fail to accept");
return -1;
}write(connfd,"hello",6);
printf("----client connect---\n");
printf("-----连接成功-----\n");
#endifstruct sockaddr_in cliaddr;
bzero(&cliaddr,0);
socklen_t len = sizeof(cliaddr);
int connfd = accept(fd,(struct sockaddr *)&cliaddr,&len);
if (connfd < 0)
{
perror("accept fail");
return -1;
}printf("----client connect---\n");
printf("client ip:%s\n",inet_ntoa(cliaddr.sin_addr));
printf("port :%d\n",ntohs(cliaddr.sin_port));return 0;
}