计算机网络 TCP通信

本文详细介绍了TCP协议的特点,包括面向连接的三次握手和四次挥手过程,以及滑动窗口机制在确认窗口尺寸和最大传输单元中的作用。此外,还讨论了TCP的可靠传输特性,如重传、校验和拥塞控制。同时提到了数据流可能导致的粘包问题及其解决方案。最后,提供了简单的TCP服务器和客户端示例代码。
摘要由CSDN通过智能技术生成

TCP:特点

  • 面向连接的(三次握手 四次挥手)

握手与挥手

 

这里在握手时  第二次握手即是请求包也是回复包

这里在三次握手的过程中TCP还进行了滑动窗口  确定了窗口尺寸  

客户端先和服务器说明他的窗口尺寸和最大传输单元

然后服务器接收这些信息  

服务器回复的时候也会将自己的窗口尺寸和最大传输单元传回给客户端

这里滑动窗口涉及到了几个协议:

  1.   1比特流协议 :一次只传1Bit
  2.  后退n协议  :当接收端从第n个包之后的包全没收到 会让发送端从第n个包开始往后 重传
  3. 选择重传协议:在接收端开辟了一个和发送端大小相同的一块缓冲区 接受完 查看缓冲区是否和发送端的数据一样  少哪个重传哪个

四次挥手:

每一次关闭一端的发送端或接收端

四次之后握手全部关闭

这里注意为什么c(客户端)会有TIMEWAIT  等待状态 而不是直接关闭

一般会等待

2MS

1MS=Maxinum Segment lifetime   WINDOWS  2min  RFC  30s

1.为了保证正常终止连接

c在最后关闭他的读的时候  并没有直接结束  而是等他的回复包真正的传给s(服务器)的时候在关闭  这是为了保证他的回复包传输的完整 进而真正的关闭s的写  如果c直接关闭了 一旦丢包  s会往回向c请求重传  但是c已经不在了  s就关闭不了了

2.为了保证老的重复分节在网络中消失  (保证垃圾数据在网络上消失)

  • 安全可靠的(重传校验 滑动窗口 拥塞控制)

  • 数据流的(可以任意拆分):

传输端发送缓冲区发m大小的数据   

接收端就收缓冲区一次只能接受1个  他会分m次依次接受

确保发送的数据都会传到接受端

但是 数据流会出现粘包问题

[如:]我传了三个包 一个包大小100   接收到的可能是一个250大小的  一个50 大小的 包

如果我们穿的包不是一个类型的数据  接收到的会出现乱码

为了解决粘包问题 :

  1. 在包的头加长度

收到包长度判断包的大小

  1. 特殊字符结尾:

每个包的结尾都会有特殊字符  特殊字符不允许再包内出现 接受的时候一个字节一个字节的收  都到特殊字符 代表当前这个包结束了(限制这能一个字节一个字节收)

  1. 固定包的大小

  1. 短链接

每一个套接字在内核里都有自己的一个缓冲区  不会粘到一块

完整代码如下

服务器端

#include <QCoreApplication>
#include<winsock2.h>
#include<iostream>
using namespace std;
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    /*
     *1.选择种类  --WSAStartup();
     *2.雇店长  --创建套接字 socket();
     *3.找地 --绑定 --bind();
     *4.店长宣传 --监听 --listen();
     *5.店长接受客人 分配给服务员  --接受链接--accept();
     *6.客人与服务员 服务员等客人说话 --recv();
     *7.回复 --send();
     *8.下班--closesocket();
     *9.关门--WASCleanup();
     *
     */


    WORD wVersionRequested;
    WSADATA wsaData;
    int err;


    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {

        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }



    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {

        WSACleanup();
        return 1;
    }
    else
        printf("The Winsock 2.2 dll was found okay\n");


//创建套接字
    SOCKET sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock==INVALID_SOCKET)
    {
        WSACleanup();
        return 1;
    }
//绑定
    sockaddr_in addrserver;
    //绑定IP
    addrserver.sin_addr.S_un.S_addr=0;
    addrserver.sin_port=htons(8899);
    addrserver.sin_family=AF_INET;
    if(SOCKET_ERROR==bind(sock,(sockaddr*)&addrserver,sizeof(addrserver)))
    {
            closesocket(sock);
            WSACleanup();
            return 1;

    }



//监听

    if(SOCKET_ERROR==listen(sock,10))

    {
        closesocket(sock);
        WSACleanup();
        return 1;

    }
//店长接受客人 分配给服务员  --接受链接--accept();
    sockaddr_in addrclient;
    int  nsize=sizeof(addrclient);
    SOCKET sockWaiter=accept(sock,(sockaddr*)&addrclient,&nsize);

    cout<<"客户端"<<inet_ntoa(addrclient.sin_addr)<<"链接了"<<endl;


//客人与服务员 服务员等客人说话 --recv();
    char szbuf[1024];
    int  nRecvNum;
    while(1)
    {
        nRecvNum=recv(sockWaiter,szbuf,sizeof(szbuf),0);
        if(nRecvNum>0)
        {
            cout<<"client say:"<<szbuf<<endl;
            cin>>szbuf;
            send(sockWaiter,szbuf,sizeof(szbuf),0);
        }
    }

//回复 --send();

//下班--closesocket();
       closesocket(sockWaiter);
       closesocket(sock);
//关门--WSACleanup();
        WSACleanup();

    return a.exec();
}

客户端

#include <QCoreApplication>
#include<winsock2.h>
#include<iostream>
using namespace std;
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
//加载库
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;


    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {

        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }



    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {

        WSACleanup();
        return 1;
    }
    else
        printf("The Winsock 2.2 dll was found okay\n");


//创建套接字
    SOCKET sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock==INVALID_SOCKET)
    {
        WSACleanup();
        return 1;
    }



//connect()

    
    //绑定IP
    sockaddr_in addrserver;
    addrserver.sin_addr.S_un.S_addr=0;
    addrserver.sin_port=htons(8899);
    addrserver.sin_family=AF_INET;
    if(SOCKET_ERROR==bind(sock,(sockaddr*)&addrserver,sizeof(addrserver)))
    {
            closesocket(sock);
            WSACleanup();
            return 1;

    }
    sockaddr_in addrWaiter;
    int  nsize=sizeof(addrWaiter);
    connect(sock,(sockaddr*)&addrWaiter,nsize);

//send()
    int  nRecvNum;
    char szbuf[1024];
    while(1)
    {
        cin>>szbuf;
        send(sock,szbuf,sizeof(szbuf),0);
        
        //recv()
        nRecvNum= recv(sock,szbuf,sizeof(szbuf),0);
        cout<<"fuwuqi say:"<<szbuf<<endl;


    }

//closesocket()
    closesocket(sock);
//WSACleanup()
    WSACleanup();
    return a.exec();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值