协议:
一组规则
分层模型结构:
OSI 七层模型 : 物、数、网、传、会、表、应
TCP/IP 4层模型:网(链路层/网络接口层)、网、传、应
应用层:http、ftp、nfd、ssh、telnet
传输层:TCP/UDP
网络层:IP、ICMP、IGMP
链路层:以太网帧协议、ARP
c/s 模型:
client-server
b/s模型:
browser-server
c/s b/s
优点: 缓存大量数据、协议选择灵活 安全性高、跨平台强、开发工作量较小
速度快
缺点:安全性低、跨平台弱、开发工作量大 不能缓存大量数据、严格遵守 http
网络传输流程:
数据没有封装之前,是不能在网络中传递
以太网帧协议:
ARP协议: 根据 ip 地址 获取 mac 地址
以太网帧协议:根据mac 地址,完成数据包传输
ip协议:
版本:IPv4、IPv6
TTL:time to live . 设置数据包在路由节点中的跳转上线。每经过一个路由节点,该值 -1,减为0的路由,有义务将改数据包丢弃
源IP: 32位。 4字节 192.168.1.108--- 点分十进制 IP地址(string) ---》 二进制
目的IP:32位 4字节
ip地址:可以在网络环境中唯一 标识一台主机。
端口号:可以在网络的一台主机上,唯一标识一个进程
ip地址+端口号:可以在网络环境中,唯一标识一个进程
UDP:
16位 : 源端口号 2^16 =65536
16位: 目的端口号。
TCP:
16位: 源端口号。 2^16 =65536
16位: 目的端口号
32 序号
32 确认号
6个标志位
16位窗口大小。 2^16
套接字:
socket本身 有插座的意思,在linux环境下, 用于表示进程间网络通信的特殊文件类型
本质为内核借助缓冲区形成的伪文件
一个文件描述符指向一个套接字
在通信中,套接字一定是成对出现的
网络字节序:
小端法:(pc本地存储) 低地址 存地位。 int a = 0x12345678
大端法: 网络存储
htonl --》本地 --》网络(IP) 192.168.1.11 --》string --》atoi--》int --》htonl--》网络字节序
htons --》本地 --》网络(port)
ntohl --》网络 --》本地(IP)
ntohs --》网络 --》本地(Port)
IP地址转换函数:
int inet_pton(int af,const char* src,void* dst); 本地字节序(string iP)--》网络字节序
af: AF_INET、AF_INET6
src: 传入,IP地址(点分十进制)
dst:传出,转换后的 网络字节序的 ip地址
返回值:
成功: 1
异常: 0 说明src 指向的不是一个 有效的 ip地址
失败: -1
const char* inet_ntop(int af,const void*src,char* dst,sockken_t size); 网络字节序--》本地字节序(string IP)
af: AF_INET、AF_INET6
src:网络字节序 IP 地址
dst: 本地字节序(string IP)
size: dst 的大小
返回值:
成功:dst
失败:NULL
sockaddr 地址结构:
struct sockaddr_in addr; man 7 ip
addr.sin_family = AF_INET/AF_INET6
addr.sin_port = htons(9527)
int dst;
inet_pton(AF_INET,"192.168.1.108",(void*)&dst);
addr.sin_addr.s_addr =dst
【*】addr.sin_addr.s_addr =htonl(INADDR_ANY ) 取出系统中有效的任意IP地址。二进制类型
bind(fd,(struct sockaddr*)&addr,size)
socket函数:
#include <sys/socket.h>
int socket(int domain, int type, int protocol); 创建一个套接字
domaian: AF_INET/AF_INET6 /AF_UNIX
type: SOCK_STREAM 、SOCK_DGRAM
protocol:0
返回值:成功: 新套接字所对应的的文件描述符
失败: -1 errno
#include<arpa/inet.h>
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen); 给socket绑定一个 地址结构(IP+port)
sockfd:socket 函数返回值
struct sockaddr_in addr;
addr.sin_family = AF_INET/AF_INET6
addr.sin_port = htons(9527)
addr.sin_addr.s_addr =htonl(INADDR_ANY ) 宏表示本地有效任意IP
addr:(struct sockaddr*)&addr
addrlen:sizeof(addr) 地址结构大小
返回值:
成功:0
失败:-1 errno
int listen(int s, int backlog); 设置同时与服务器建立连接的上限数。(同时进行3次握手的客户端数量)
sockfd: socket 函数返回值
backlog:上限数值 。最大值 128
返回值:
成功:0
失败: -1 errno
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
阻塞等待客户端建立连接,成功的话,返回一个与客户端成功连接的socket 文件描述符
s:socket函数返回值
addr:传出参数 成功与服务器建立连接的那个客户端的地址结构(IP+ port)
socklen_t clit_addr_len = sizeof(addr)
addrlen:传入传出参数。 &clit_addr_len
入:addr的大小 出:客户端addr实际大小
返回值:
成功:能与服务器进行数据通信的 socket 对应的文件描述。
失败: -1 ,errno
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
使用现有的 socket 与服务器建立连接
sockfd: socket 函数返回值
addr:传入参数。服务器地址结构
addrlen: 服务器地址结构的大小
返回值;
成功: 0
失败:-1 errno
若果不用bind 绑定客户端地址结构,采用“隐式绑定”
TCP通信流程分析:
server:
1.socket( ) 创建socket
2.bind() 绑定服务器地址结构
3.listen() 设置监听上限
4.accept() 阻塞监听客户端连接
5.read(fd) 读socket获取客户端数据
6.小--大写 toupper()
7.write(fd)
8.close();
client:
1.socket() 创建socket
2.connect() 与服务器建立连接
3.write() 写数据到 socket
4.read() 读转换后的数据
5.显示读取结果
6.close()
//server
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<ctype.h>
#define SERV_PORT 9527
void sys_err(const char* str){
perror(str);
exit(1);
}
int main(){
int lfd = 0,cfd=0;
int ret;
char buf[BUFSIZ],client__IP[1024];
struct sockaddr_in serv_addr,clit_addr;
socklen_t clit_addr_len;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
lfd =socket(AF_INET,SOCK_STREAM,0);
if(lfd==-1){
sys_err("socket error");
}
bind(lfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
listen(lfd,128);
clit_addr_len = sizeof(clit_addr);
cfd = accept(lfd,(struct sockaddr*)&clit_addr,&clit_addr_len);
if(cfd==-1){
sys_err("accept error");
}
printf("client ip :%s port:%d\n"
,inet_ntop(AF_INET,(void*)&clit_addr.sin_addr.s_addr,client__IP,sizeof(client__IP)),
ntohs(clit_addr.sin_port));
while(1){
ret=read(cfd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,ret);
for(int i =0;i<ret;++i){
buf[i]=toupper(buf[i]);
}
write(cfd,buf,ret);
}
close(lfd);
close(cfd);
return 0;
}
=========================================================================================
//client
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<ctype.h>
#define SERV_PORT 9527
void sys_err(const char* str){
perror(str);
exit(1);
}
int main(){
int cfd;
char buf[BUFSIZ];
struct sockaddr_in serv_addr; //服务器地址结构
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET,"127.0.0.1",&serv_addr.sin_addr.s_addr);
cfd = socket(AF_INET,SOCK_STREAM,0);
if(cfd==-1){
sys_err("socket error");
}
int ret=connect(cfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
if(ret!=0){
sys_err("connect error");
}
while(1){
write(cfd,"hello\n",6);
ret=read(cfd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,ret);
sleep(1);
}
close(cfd);
return 0;
}