网络
网络是由若干结点和连接这些结点的链路组成,网络中的结点可以是计算机、交换机、路由器等设备。
网络设备有:交换机、路由器、集线器
传输介质有:双绞线、同轴电缆、光纤
互联网
把多个网络连接起来就构成了互联网。目前最大的互联网就是我们常说的因特网。
IP地址(在网络中唯一标识一台主机)
IP地址就是给因特网上的每一个主机(或路由器)的每一个接口分配的一个在全世界范围唯一的标识符。IP地址因其特殊的结构是我们可以在因特网上很方便地进行寻址。每个IP地址由网络号和主机号构成。
(网络号+主机号一共32位)
IP地址分为IPV4和IPV6两种类别格式,IPV4是类似“A.B.C.D”的格式,是32位的,用“.‘分成四个段,每个段是8个位(0-255)。IPV6地址是128位,格式类似”XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX“,用”:“分成8个段,每个段16位,用4个16进制数表示。
由于每类地址的开头是固定的,因此每类地址都有自己的范围:
A类:IP地址范围为:0.0.0.0~127.255.255.255。
(网络号7位,主机号24位,开头第一位是0)
B类:IP地址范围为:128.0.0.0~191.255.255.255。
(网络号14位,主机号16位,开头前两位是1、0)
C类:IP地址范围为:192.0.0.0~127.223.255.255。
(网络号21位,主机号8位,开头前三位是1、1、0)
在Linux中使用命令”ifconfig“可以查看自己的ip地址。
网络协议:
网络协议就是一组网络规则的集合,是我们共同遵守的约定或标准。常见的协议:
HTTP:超文本传输协议
FTP:文件传输协议
TELNET:是internet远程登录服务的标准协议
TCP:传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层协议
UDP:用户数据报协议
IP:Interner Protocol简称IP,又译为网络协议或互联网协议
ICMP:因特网控制报文协议
ARP:地址解析协议,是根据IP地址获取MAC地址的协议
RARP:逆地址解析协议
网络分层模型
OSI的7层模型与tcp/ip协议族体系的4层结构
OSI模型 tcp/ip模型
应用层 应用层
表示层 传输层
会话层 网络层
传输层 数据链路层
网络层
数据链路层
物理层
分层的好处
1、各层之间是独立的
2、灵活性好
3、结构上可分割开
4、易于实现和维护
5、能促进标准化工作
socket网络编程
1、主机字节序列和网络字节序列
主机字节序列分为大端字节序和小端字节序,不同的主机采用的字节序列可能不同。大端字节序是指整数的高位字节存储在内存的低地址处,而低位字节
存储在内存的高地址处。小端字节序则是指整数的高位字节存储在内存的高地址处,低位字节存储在内存的低地址处。在两台使用不同字节序的主机之间传递数据时,可能会出现冲突。所以,在将数据发送到网络时规定整形数据使用大端字节序,所有也把大端字节序称为网络字节序。
uint32_t htonl(uint32_t hostlong);//长整型的主机字节序转网络字节序
uint32_t ntohl(uint32_t netlong);//长整型的网络字节序转主机字节序
uint16_t htons(uint16_t hostshort);//短整型的主机字节序转网络字节序
uint16_t ntohs(uint16_t netshort);//短整型的网络字节序转主机字节序
in_addr_t inet_addr(const char* cp);//字符串表示的IPV4地址转化为网络字节序
char* inet_ntoa(struct in_addr in);//IPV4地址的网络字节序转换为字符串表示
TCP编程
Linux中
服务器端
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);//创建监听套接字
assert(sockfd != -1);
struct sockaddr saddr,caddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = bind(sockfd,(struct saddr*)&saddr,sizeof(saddr));//绑定ip和port
assert(res != -1);
res = listen(sockfd,5);//设置监听队列长度
while(1)
{
int len = sizeof(caddr);
int c = accept(sockfd,(struct caddr*)&caddr,&len);//连接套接字
if(c<0)
{
continue;
}
while(1)
{
int buff[128] = {0};
int n = recv(c,buff,127,0);
if(n <= 0)
{
break;
}
ptintf("buff-%s\n",buff);
send(c,"ok",2,0);
}
}
close(c);
}
客户端
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd != -1);
struct sockaddr saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
assert(res != -1);
while(1)
{
printf("input:\n");
char buff[128] = {0};
fgets(buff,128,stdin);
if(strncmp(buff,"end",3)==0)
{
break;
}
send(sockfd,buff,strlen(buff),0);
memset(buff,0,128);
recv(sockfd,buff,127,0);
printf("buff=%s\n",buff);
}
close(sockfd);
}
UDP编程
服务器端
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
int sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建监听套接字
assert(sockfd != -1);
struct sockaddr saddr,caddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = bind(sockfd,(struct saddr*)&saddr,sizeof(saddr));//绑定ip和port
assert(res != -1);
while(1)
{
char buff[128] = {0};
int len = sizeof(caddr);
recvfrom(sockfd,buff,127,0,(struct sockaddr*)&caddr,&len);
printf("buff=%s\n,port:%d\n",buff,ntohs(caddr.sin_port));
sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,sizeof(caddr));
}
close(sockfd);
}
客户端
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
int sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建监听套接字
assert(sockfd != -1);
struct sockaddr saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
while(1)
{
char buff[128] = {0};
printf("input:\n");
char buff[128] = {0};
fgets(buff,128,stdin);
if(strncmp(buff,"end",3)==0)
{
break;
}
sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&saddr,sizeof(saddr));
memset(buff,0,128);
int len = sizeof(saddr);
recvfrom(sockfd,buff,127,0,(struct sockaddr*)&saddr,&len);
printf("buff=%s\n",buff);
}
close(sockfd);
}
TCP与UDP基本区别
1.TCP是面向连接的,而UDP是无连接的,即发送数据之前不需要建立连接
2.TCP提供可靠的服务。通过TCP连接传送的数据,无差错,不丢失,不重复,且按顺序到达,UDP尽最大努力交付,不保证可靠交付。
3.TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如视频会议)
4.每一天TCP连接只能是点到点的,UDP支持一对一,一对多,多对一和多对多的交互通信。
5.TCP首部开销20字节,UDP的首部开销小,只有8个字节
6.TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
7.TCP有应答确认,超时重传机制,乱序会重排,会丢弃重复报文
UDP应用场景:
1.面向数据报方式
2.网络数据大多为短消息
3.拥有大量Client
4.对数据安全性无特殊要求
5.网络负担非常重,但对响应速度要求高
具体编程实时的区别
1.socket()的参数不同
2.UDP Server不需要调用listen和accept
3.UDP收发数据用recvfrom/sendto
4.TCP:地址信息在connect/accept时确定
5.UDP:在sendto/recvfrom函数中每次需要指定地址信息
编程区别
通常我们在说到网络编程时默认是指TCP编程,即用socket函数创建一个socket用于TCP通讯,即socket(AF_INET,SOCK_STREAM,0),这表示建立一个socket用于流式网络通讯。
SOCK_STREAM这种服务是面向连接的,即每次收发数据之前必须通过connect建立连接,也是双向的,即任何一方都可以收发数据,协议本身提供了一些保障机制保证它是可靠的、有序的,即每个包按照发送的顺序到达接收方。
而SOCK_DGRAM是数据服务,它是无连接的、不可靠的,因为通讯双方发送数据后不知道对方是否已经收到数据,是否正常收到数据。任何一方建立一个socket以后就可以用sendto发送数据,也可以用recvfrom接收数据。根本不关心对方是否存在,是否发送了数据。他的特点是通讯速度比较快。