Linux9.12 day20 tcp协议特点

9.12 tcp协议特点

tcp客户端编程流程:

ser 服务器端

socket()
bind() ip+port
listen()
accept()
recv()
send()
close()

cli 客户端
socket()
connect() 开始进行三次握手 建立连接
send()
recv()
close() 开始进行四次挥手

tcp协议特点:面向连接的 可靠的 流式服务
udp协议特点:无连接 不可靠的 数据服

握手挥手对于程序员透明 无法看到
send() recv() 用户无法干预

抓包 tcpdump
命令: tcpdump -i ens33 -mt -S ‘(src 192.168.43.10 and dst 192.168.43.15)or(src192.168.43.15 and dst 192.168.43.10)’

四次挥手发生在客户端或者服务端执行close()关闭连接的时候:

主动断开方 被动断开方
— FIN seq = i -->
<-- ACK = i+1 —
<-- FIN seq = j —
— ACK = j+1 -->

四次挥手可以演化为三次

程序结束后 内核会维持连接一段时间 直到完成四次挥手才断开连接

保证tcp协议可靠性:

1.应答确认机制 超时重传

2.乱序重排

3.通过滑动窗口控制流量速度
滑动窗口大小可调整 进行流量控制
发送缓冲区 send() --滑动窗口–> 接收缓冲区 recv()

4.去重
(A发送数据 B收到 B发送收到信号 中途丢失 A以为B未收到超时重发 B收到两个数据对比序号 相同丢掉一个 此为去重操作)

流式服务特点:

多次发送的数据有可能会被对方一次收到

粘包:
本应分开收到的数据被一次接收粘连在一起导致连接阻塞

(eg:发送长方体长为7 宽为2 高为3
send(7) send(2) send(3)
recv(723) recv() 无法接受到数据阻塞 recv()
本应该为recv(7) recv(2) recv(3) )

tcp状态转移图
三次握手

四次挥手:
主动关闭 -->TIME_WAIT
被动关闭 -->LAST_ACK

TIME_WAIT 状态维持的原因: !!!!!
1.可靠地终止TCP连接
2.保证让迟来的TCP报文段有足够的时间被识别并丢弃

多线程代码实现:

(ser.c)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

int create_socket();

void* thread_fun(void* arg)
{
    int c = (int)arg;
    while(1)
    {
        char buff[128] = {0};
        int n = recv(c,buff,1,0);
        if(n <= 0)
        {
            break;
        }
        printf("recv(%d)=%s\n",c,buff);
        send(c,"ok",2,0);
    }
}

int main()
{
    int sockfd = create_scket();
    assert(sockfd != -1);
    while(1)
    {
        struct sockaddr_in caddr; //存放客户端地址
        int len = sizeof(caddr);
        int c = accept(sockfd,(struct sockaddr*)&caddr,&len);
        if(c < 0)
        {
            continue;
        }

        //启动线程
        pthread_t id;
        pthread_create(&id,NULL,thread_fun,(void*)c);
    }
}

int create_socket()
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        return -1;
    }

    struct sockaddr_in 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(-1 == res)
    {
        return -1;
    }

    res = listen(sockfd,5);
    if(-1 == res)
    {
        return -1;
    }

    return sockfd;
}

(fork.c)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

int create_socket();

int main()
{
    signal(SIGCHLD,SIG_IGN);
    int sockfd = create_socket();
    assert(sockfd != -1);

    while(1)
    {
        struct sockaddr_in caddr; //存放客户端地址
        int len = sizeof(caddr);
        int c = accept(sockfd,(struct sockaddr*)&caddr,&len);
        if(c < 0)
        {
            continue;
        }

        pid_t pid = fork();
        if(pid == -1)
        {
            close(c);
            continue;
        }

        if(pid == 0)
        {
            while(1)
            {
                char buff[128] = {0};
                int n = recv(c,buff,127,0);
                if(n <= 0)
                {
                    break;
                }

                printf("buff=%s\n",buff);
                send(c,"ok",2,0);
            }

            close(c); //子进程 关闭
            printf("client close\n");
            exit(0);
        }
        close(c);  //父进程 关闭
    }
}

int create_socket()    ///可能有错误!!!
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        return -1;
    }

    struct sockaddr_in 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(-1 == res)
    {
        return -1;
    }

    res = listen(sockfd,5);
    if(-1 == res)
    {
        return -1;
    }
    return sockfd;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值