Linux网络编程——协议(C/S模型进行通信)
文章目录
- 协议:
- 分层模型结构:
- 网络字节序:
- IP地址转换函数:
- socaddr地址结构:
- socket函数:
- CS模型TCP通信
- 服务端:
- 客户端:
- TCP通信时序
- 三次握手:
- 四次挥手:
协议:
- 一组规则。
分层模型结构:
-
OSI七层模型:物、数、网、传、会、表、应
-
TCP/IP 4层模型。网(链路层/网络接口层)、网、传、应
- 应用层:http、 ftp、nfs、 ssh、 te1neto 。 。
- 传输层:TCP、UDP
- 网络层:IP、ICMP、IGMP
- 链路层:以太网帧协议、ARP
-
B/S
优点:缓存大量数据、协议选择灵活、速度快 缺点:安全性、跨平台、开发工作量较小
-
C/S
优点:安全性、跨平台、开发工作量较小 缺点:不能缓存大量数据、严格遵守http
-
网络传输流程:
数据没有封装之前,是不能在网络中传递。 -
以太网帧协议;
ARP协议。根据Ip地址获取mac地址。
以太网帧协议:根据mac地址,完成数据包传输。 -
IP协议:
版本:IPv4、IPv6--4位 TTL: time to live 。设置数据包在路由节点中的跳转上限。每经过一个路由节点,该值-1,减为O的路由,有义务将该数据包丢弃 源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 = 65536
网络字节序:
-
小端法:(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) ;
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,socklen_t
size); 网络字节序—〉本地字节序(string IP)
af: AF_INET、AF_INET6
src:网络字节序IP地址
dst:本地字节序(string IP)size:dst的大小。
返回值:成功: dsto;失败:NULL
socaddr地址结构:
struct sockaddr_in addr ;
addr.sin_family = AF_INET/AF_INET6
addr.sin_port = htons(9527);
int dst ;
inet_pton(AF_INET,“192.157.22.45",(void *)&dst) ;
addr. sin_addr.s_addr = dst;
【*】addr.sin_addr.s_addr = hton1(INADDR_ANY ); 取出系统中有效的任意IP地址。二进制类型。
- bind(fd,(struct sockaddr *)&addr,size);
socket函数:
include <sys/socket.h>
int socket(int domain, int type, int protoco1);
创建一个套接字
domain: AF_INET、AF_INET6、AF_UNIX
type: SOCK_STREAI、SOCK_DGRAM
protocol: 0
返回值:
成功:新套接字所对应文件描述符
失败: -1 errno
int bind(int sockfd,const struct sockaddr *addr,sock1en_t adtrlen);
给socket绑定一个地址结构(IP+port)
sockfd: socket函数返回值
struct sockaddr_in addr ;
addr. sin_family = AF_INET;
addr.sin_port = htons(8888) ;
addr.sin_addr. s_addr = hton1 (INADDR_ANY) ;
addr: (struct sockaddr *)&addr
addrlen: sizeof(addr)地址结构的大小。
返回值:
成功:0
失败: -1 errno
int listen(int sockfd, int back1og);
设置同时与服务器建立连接的上限数。(同时进行3次握手的客户端数量)
sockfd: socket函数返回值
backlog:上限数值。最大值128.
返回值:
成功:0
失败:-1 errno
int accept(int sockfd, struct sockaddr *addr,socklen_t *addr1en);
阻塞等待客户端建立连接,成功的话,返回一个与客户端成功连接的socket文件描述符
sockfd: socket函数返回值
addr:传出参数。成功与服务器建立连接的那个客户端的地址结构(IP+port)
socklen_t clit_addr _len = sizeof(addr);
addrlen:传入传出。&clit_addr_len
入:addr的大小。出:客户端addr实际大小。
返回值:
成功:能与服务器进行数据通信的 socket对应的文件描述。
失败:-1 , errno
int cornect(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
使用现有的 socket与服务器建立连接
sockfd: socket函数返回值
struct sockaddr_in srv_addr ; //服务器地址结木
srv_addr.sin_farmi1y = AF_INET;
srv_addr.sin_port = 9527 //跟服务器bind时设定的 port完全一致。
inet_pton(AF_INET,“服务器的IP地址",&srv_adrr.sin_addr.s_addr);
addr:传入参数。服务器的地址结构
addrlen:服务器的地址结构的大小
返回值:
成功:0
失败: -1 errno
如果不使用bind绑定客户端地址结构,采用"隐式绑定”.
CS模型TCP通信
服务端:
int main(int argc,char *argv[])
{
int lfd = 0,cfd = 0;
int ret;
char buf[BUFSIZ];//4096
struct sockaddr_in serv_addr,clit_addr;
socklen_t clit_addr_len;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PROT);//SERV_PROT 9527
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
lfd = socket(AF_INET,SOCK_STREAM,0);
if(lfd = -1){
//-1: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){
//-1:error
}
ret = read(cfd,buf,sizeof(buf));
//处理数据,转换成大写字母
for(int i = 0;i < ret;i++)
buf[i] = toupper(buf[i]);
//
write(cfd,buf,ret);
close(lfd);
close(cfd);
return 0;
}
客户端:
int main(){
int cfd;
char buf[BUFSIZ];
struct sockaddr_in serv_addr;//服务器地址结构
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(9527);//SERV_PROT 9527
inet_pton(AF_INET,"127.0.0.1",&serv_addr.sin.s_addr );
cfd = socket(AF_INET,SOCK_STREAM,0);
if(cfd == -1){
//error
}
int ret = connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
if(ret != 0){
//error
}
write(cfd,"hello",5);
read(cfd,buf,sizeof(buf));
return 0;
}
TCP通信时序
三次握手:
- 主动发起连接请求端,发送 SYN标志位,请求建立连接。携带序号号、数据字节数(O)、滑动窗口大小。
- 被动接受连接请求端,发送ACK标志位,同时携带SYN 请求标志位。携带序号、确认序号、数据字节数(O)、滑动窗口大小
- 主动发起连接请求端,发送 ACK标志位,应答服务器连接请求。携带确认序号。
四次挥手:
-
主动关闭连接请求端,发送FIN标志位。
-
被动关闭连接请求端,应答ACK标志位。
-----半关闭完成。 -
被动关闭连接请求端,发送FIN 标志位。
-
主动关闭连接请求端,应答ACK标志位。
-----连接全部关闭