Linux网络编程——协议(C/S模型进行TCP通信)-创新互联
- 协议:
- 分层模型结构:
- 网络字节序:
- IP地址转换函数:
- socaddr地址结构:
- socket函数:
- CS模型TCP通信
- 服务端:
- 客户端:
- TCP通信时序
- 三次握手:
- 四次挥手:
- TCP状态时序图:
- 2MSL时长:
- 半关闭:
协议:
- 一组规则。
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)
- 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
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);
includeint 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标志位。
-----连接全部关闭
1. 主动发起连接请求端:CLOSB --发送STNM-- SND_SYNM --接收 ACK、SIN -- SEND_STN
--发送 ACX--ESTABLTSHED(数据通信态)
2. 主动关闭连接请求端:ESTABLISHED(数据通信态)-- 发送FIN-- FIN_WATT_1 --接收ACK
-- FIM_VAIT_2(半关闭)--接收对端发送FIN --FIN_VAIT_2(半关闭)-- 回发ACK
-- TIME_VAIT(只有主动关闭连接方,会 经历该状态)--等2MSL时长-- CLOSE
3.被动接收连接请求端:CLOSB -- LISTENM --接收STNM -- LISTEN --发送 ACX、STNM
-- SIM_RCVD--接收ACX--- ESTABLISED(数据通信态
4.被动关闭连接请求端:ESTABLISHED(数据通信态)--接收FIN ESTABLISHED(数据通
信态)--发送ACK-- CLOSB_WAIT(说明对端【主动关闭连接端】处于半关闭
状态)--发送FIN-- LAST_ACK -- 接收ACK -- CLOSE
2MSL时长:一定出现在【主动关闭连接请求端】。— TIME_亚AIT
保证,最后一个ACK能成功被对端接收。(等待期间,对端没收到我发的ACK,对端会再次发送FIN请求。)
半关闭:通信双方中,只有一端关闭通信。— FIN_WAIT_2
close (cfd) ;
shutdown(int fd, int how);
how :
SHUT_RD关读端
SHUT_WR 关写端
SHUT_RDR关读写
shutdown在关闭多个文件描述符应用的文件时,采用全关闭方法。close,只关闭一个。
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
分享标题:Linux网络编程——协议(C/S模型进行TCP通信)-创新互联
网页URL:http://hbruida.cn/article/gecgd.html