Linux-udp-http协议-tcp状态转移图

一.tcp状态转移图

1.下图为TCP状态转移图,此图包含三次握手和四次挥手,其中三次握手比快。

①三次握手:由客户端主动打开,给服务端发送SYN,客户端变为SYN_SENT,服务端收到SYN为第一次握手。服务端给客户端发送SYN,ACK,客户端收到SYN,ACK为第二次握手。客户端给服务端发送确认号ACK,服务端收到ACK,为第三次握手。完成三次握手后,客户端与服务端都变成ESTABLISHED(已完成三次握手状态)

②四次挥手:

       不论是客户端还是服务端,在进行close时进行挥手。当有一方先进行close操作就是主动关闭,另一方就是被动关闭。(这里假设客户端先关闭)客户端发送FIN,服务端接收FIN,为第一次挥手,此时服务端变为CLOSE_WAIT,客户端变为FIN_WAIT_1。当服务端发送ACK,客户端收到ACK为第二次挥手,此时客户端变为FIN_WAIT_2。当服务端发送FIN,客户端接收FIN为第三次挥手,此时服务端变为LAST_ACK。当客户端发送ACK,服务端接收ACK为第四次挥手,此时客户端变为TIME_WAIT,服务端消失。

  三次挥手:

   (这里假设客户端先关闭)客户端发送FIN,服务端接收FIN,为第一次挥手,此时服务端变为CLOSE_WAIT,客户端变为FIN_WAIT_1。当服务端发送ACK和FIN,客户端收到FIN和ACK,为第二次挥手,此时服务端变为LAST_ACK。当客户端发送ACK,服务端收到ACK,为第三次挥手,此时客户端变为TIME_WAIT,服务端消失。

  客户端与服务端同时关闭:

   双方同时给对方发送FIN,此时双方状态都变成FIN_WAIT_1。之后双方同时接收FIN和发送ACK,此时就是同时关闭,双方状态都变为CLOSING。之后双方同时接收ACK,状态都变成TIME_WAIT。

2.TIME_WAIT:存活时间是一个报文最大生存时间的两倍。(大概2min)

   为什么要有TIME_WAIT状态:

注:①当有TIME_WAIT状态,当客户端发送ACK后,让服务端有足够的时间接收ACK。就可以顺利结束TCP连接。要是没有TIME_WAIT状态,服务端万一没有接收到ACK,根据超时重传机制,服务端重新发来的FIN,客户端早已经结束,就不认识这个FIN了,挥手就无法准确进行。

②若是没有TIME_WAIT状态,当连接关闭后,端口号被释放,此时可能还有一些数据在路上没有发送过来,当要是有其他进程连接这个端口号,可能会产生混乱。

3.怎么解决connect长时间阻塞:给connect设置一定次数循环,当循环结束还没有连接上就退出。或者设定一定的时间,若时间到了还没有连接上就退出等等。(正常TCP自己结束等待的时间较长)

二.传输层udp的编程流程(短信)

1.服务端

socket(int domain(地址族ipv4/ipv6),int type(服务类型,tcp->流式服务,udp->数据报服务),int protocol(协议版本,目前恒为0))-->创建套接字

②bind(int sockfd(套接字描述符),const struct sockaddr *addr(使用哪个IP的哪个端口),socklen_t addrlen(指针指向空间的大小))-->指定IP与端口

③recvfrom(int sockfd(套接字描述符),void * buf(传到哪个buff中),size_t len(buff多大),int flags(标志位),struct sockaddr * src_addr(套接字的地址结构-->收到的数据存进去,记录了发送者的IP与端口),socklen_t *addrlen(套接字地址结构大小))-->接收数据

④sendto(int sockfd(监听套接字),const void * buf(待发送的数据),size_t len(发送数据的大小),int flags(标志位),const struct sockaddr * dest_addr(套接字的地址结构-->数据去往的ip与端口),socklen_t addrlen(套接字地址结构大小))-->发送数据

⑤close(int fd(套接字))-->关闭描述符

2.客户端

①socket(int domain(地址族ipv4/ipv6),int type(服务类型,tcp->流式服务,udp->数据报服务),int protocol(协议版本,目前恒为0))-->创建套接字

②sendto(int sockfd(监听套接字),const void * buf(待发送的数据),size_t len(发送数据的大小),int flags(标志位),const struct sockaddr * dest_addr(套接字的地址结构-->数据去往的ip与端口),socklen_t addrlen(套接字地址结构大小))-->发送数据

③recvfrom(int sockfd(套接字描述符),void * buf(传到哪个buff中),size_t len(buff多大),int flags(标志位),struct sockaddr * src_addr(套接字的地址结构-->收到的数据存进去,记录了发送者的IP与端口),socklen_t *addrlen(套接字地址结构大小))-->接收数据

④close(int fd(套接字))-->关闭连接

3.实现客户端与服务端的连接,客户端从键盘输入给服务端可以发送消息,服务端收到打印出来并返回ok,客户端收到后将ok也打印到屏幕上。

①服务端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
int main()//udp循环的接收
{
    int sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd == -1)
    {
        printf("sockfd err\n");
        exit(1);
    }
 
    struct sockaddr_in saddr,caddr;
    menset(&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 sockaddr*)&saddr,sizeof(saddr));
    if(res==-1)
    {
        printf("res err\n");
        exit(1);
    }
  
    while(1)
    {
        int len=sizeof(caddr);
        char buff[128]={0};
        recvfrom(sockfd,buff,127,0,(struct sockaddr*)&caddr,&len);
        printf("n=&s\n",buff);

        sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,len);
     }
}

②客户端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
int main()
{
    int sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd==-1)
    {
        exit(1);
    }

    struct sockaddr_in saddr;//代表服务器的IP和端口
    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");
        fgets(buff,128,stdin);
        if(strncmp(buff,"end",3) == 0)
        {
            break;
        }

        sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&saddr,sizeof(saddr));

        menset(buff,0,sizeof(buff));
        int len=sizeof(saddr);
        recvfrom(sockfd,buff,127,0,(struct sockaddr*)&saddr,&len);
        printf("buff=&s\n",buff);
    }
    close(sockfd);
    exit(0);
}

4.udp与tcp不同没有接收缓冲区,发送端发送的数据是直接交给udp数据报,再由数据报直接交给接收端,没来得及发送的数据直接就丢失了。即发送一次就接收一次,发送两次就接收两次。

如:

5.下载文件适合那种模式:TCP好,因为TCP有超时重发的机制,当文件下载到一半没成功,继续下载可以接着上次下载的地方下载,且文件下载要有可靠性。

    视频聊天:udp好,因为视频一旦断开,信息的交互就直接结束,不再存储信息,下次视频就是新的开始。

6.udp占用了6000号端口,那tcp可不可以用6000号端口:可以,不同协议之间不相关。可以通过以下这个命令查看。

7.一个进程可不可以创建多个套接字:可以的(如两个套接字1,2进行listen,一个listen 1,一个listen 2)

   一个进程可不可以使用两个及以上的端口:可以的

8.udp特点:无连接,不可靠的,数据报服务(客户端发几次服务端就收几次,反之也一样,不考虑丢包的问题)

三.http协议

1.http协议又叫超文本传输协议(可以传输视频,照片等等),一般用在浏览器和服务器通信的时候。

2.http协议是应用层的协议。使用的端口是80。https协议是更为安全的,使用的端口为443。它在传输层用的是tcp协议。

3.在命令提示符界面可以使用ping www.baidu.com可以拿到百度的Ip地址。

4.http回复状态码:

5.在网页中输入www.baidu.com会发生什么事:首先通过DNS解析拿到IP地址,并且端口号固定为80。有了IP与端口就可以执行connect,然后就会建立tcp连接。然后浏览器会发起请求。服务器会进行应答。(一次来回是短连接)(重复来回是长连接)

请求报文:

应答报文:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值