TCP:特点
握手与挥手
这里在握手时 第二次握手即是请求包也是回复包
这里在三次握手的过程中TCP还进行了滑动窗口 确定了窗口尺寸
客户端先和服务器说明他的窗口尺寸和最大传输单元
然后服务器接收这些信息
服务器回复的时候也会将自己的窗口尺寸和最大传输单元传回给客户端
这里滑动窗口涉及到了几个协议:
四次挥手:
每一次关闭一端的发送端或接收端
四次之后握手全部关闭
这里注意为什么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 大小的 包
如果我们穿的包不是一个类型的数据 接收到的会出现乱码
为了解决粘包问题 :
收到包长度判断包的大小
每个包的结尾都会有特殊字符 特殊字符不允许再包内出现 接受的时候一个字节一个字节的收 都到特殊字符 代表当前这个包结束了(限制这能一个字节一个字节收)
每一个套接字在内核里都有自己的一个缓冲区 不会粘到一块
完整代码如下
服务器端
- #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();
- }