zoukankan      html  css  js  c++  java
  • <网络> TCP:C/S模式设计 以及相关知识

    一.服务器端Server

    1.基本思路:

    ①加载库:WSAStartup();

    ②创建套接字:socket();

    ③选址绑定:bind():

    ④监听:listen();

    ⑤接受客户端连接:accept();

    ⑥收发数据:recv - send

    ⑦关闭套接字:closesocket();(两个)

    ⑧卸载库:WSACleanup();

    2.代码实现:

     1 #include<iostream>
     2 #include<WinSock2.h>
     3 using namespace std;
     4 
     5 // Need to link with Ws2_32.lib
     6 #pragma comment(lib, "ws2_32.lib")
     7 
     8 int main()
     9 {
    10     //1.选择一个种类:加载库
    11     WORD wVersionRequested;
    12     WSADATA wsaData;
    13     int err;
    14 
    15 /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
    16     wVersionRequested = MAKEWORD(2, 2);
    17 
    18     err = WSAStartup(wVersionRequested, &wsaData);
    19     if (err != 0) {
    20         /* Tell the user that we could not find a usable */
    21         /* Winsock DLL.                                  */
    22         printf("WSAStartup failed with error: %d
    ", err);
    23         return 1;
    24     }
    25 
    26 /* Confirm that the WinSock DLL supports 2.2.*/
    27 /* Note that if the DLL supports versions greater    */
    28 /* than 2.2 in addition to 2.2, it will still return */
    29 /* 2.2 in wVersion since that is the version we      */
    30 /* requested.                                        */
    31 
    32     if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
    33         /* Tell the user that we could not find a usable */
    34         /* WinSock DLL.                                  */
    35         printf("Could not find a usable version of Winsock.dll
    ");
    36         WSACleanup();
    37         return 1;
    38     }
    39     else
    40         printf("The Winsock 2.2 dll was found okay
    ");
    41 
    42     //2.雇佣店长:创建套接字 socket
    43     SOCKET sockListen = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    44     if(sockListen == INVALID_SOCKET)
    45     {
    46         WSACleanup();
    47         return 1;
    48     }
    49 
    50     //3.选址:绑定 bind
    51     sockaddr_in addrServer;
    52     addrServer.sin_family = AF_INET;
    53     addrServer.sin_port = htons(1234);
    54     addrServer.sin_addr.S_un.S_addr = INADDR_ANY;
    55     
    56     if(bind(sockListen,(const sockaddr *)&addrServer,sizeof(addrServer)) == SOCKET_ERROR)
    57     {
    58         closesocket(sockListen);
    59         WSACleanup();
    60         return 1;
    61     }
    62 
    63     //4.店长开始宣传:监听 listen
    64     if(SOCKET_ERROR == listen(sockListen,3))
    65     {
    66         closesocket(sockListen);
    67         WSACleanup();
    68         return 1;
    69     }
    70 
    71     //5.把客人拉进店里 交给服务员:接受客户端连接
    72     SOCKET sockWaiter = accept(sockListen,NULL,NULL);
    73 
    74     //6.服务员 客人:recv - send
    75     char szbuf[1024] = {0};
    76     while(1)
    77     {
    78         int nres = recv(sockWaiter,szbuf,sizeof(szbuf),0);
    79         if(nres > 0)
    80         {
    81             cout << szbuf << endl;
    82             cin >> szbuf;
    83             send(sockWaiter,szbuf,sizeof(szbuf),0);
    84         }
    85     }
    86 
    87     //7.客人离开 服务员下班
    88     closesocket(sockWaiter);
    89 
    90     //8.店长下班
    91     closesocket(sockListen);
    92 
    93     //9.挂门:卸载库
    94     WSACleanup();
    95 
    96     system("pause");
    97     return 0;
    98 }

    二.客户端Client

    1.基本思路:

    ①加载库:WSAStartup();

    ②创建套接字:socket();

    ③connect();

    ④收发数据:recv - send

    ⑤关闭套接字:closesocket();

    ⑥卸载库:WSACleanup();

    2.代码实现:

     1 #include<iostream>
     2 #include<WinSock2.h>
     3 using namespace std;
     4 
     5 // Need to link with Ws2_32.lib
     6 #pragma comment(lib, "ws2_32.lib")
     7 
     8 int main()
     9 {
    10     //1.选择一个种类:加载库
    11     WORD wVersionRequested;
    12     WSADATA wsaData;
    13     int err;
    14 
    15 /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
    16     wVersionRequested = MAKEWORD(2, 2);
    17 
    18     err = WSAStartup(wVersionRequested, &wsaData);
    19     if (err != 0) {
    20         /* Tell the user that we could not find a usable */
    21         /* Winsock DLL.                                  */
    22         printf("WSAStartup failed with error: %d
    ", err);
    23         return 1;
    24     }
    25 
    26 /* Confirm that the WinSock DLL supports 2.2.*/
    27 /* Note that if the DLL supports versions greater    */
    28 /* than 2.2 in addition to 2.2, it will still return */
    29 /* 2.2 in wVersion since that is the version we      */
    30 /* requested.                                        */
    31 
    32     if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
    33         /* Tell the user that we could not find a usable */
    34         /* WinSock DLL.                                  */
    35         printf("Could not find a usable version of Winsock.dll
    ");
    36         WSACleanup();
    37         return 1;
    38     }
    39     else
    40         printf("The Winsock 2.2 dll was found okay
    ");
    41 
    42     //
    43     SOCKET sockClient = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    44     if(sockClient == INVALID_SOCKET)
    45     {
    46         WSACleanup();
    47         return 1;
    48     }
    49 
    50     //
    51     sockaddr_in addrClient;
    52     addrClient.sin_family = AF_INET;
    53     addrClient.sin_port = htons(1234);
    54     addrClient.sin_addr.S_un.S_addr = inet_addr("192.168.2.167");
    55     
    56     if(connect(sockClient,(const sockaddr *)&addrClient,sizeof(addrClient)) == SOCKET_ERROR)
    57     {
    58         closesocket(sockClient);
    59         WSACleanup();
    60         return 1;
    61     }
    62 
    63     //
    64     char szbuf[1024] = {0};
    65     while(1)
    66     {
    67         cin >> szbuf;
    68         send(sockClient,szbuf,sizeof(szbuf),0);
    69 
    70         int nres = recv(sockClient,szbuf,sizeof(szbuf),0);
    71         if(nres > 0)
    72         {
    73             cout << szbuf << endl;
    74         }
    75     }
    76 
    77     //
    78     closesocket(sockClient);
    79 
    80     //卸载库
    81     WSACleanup();
    82 
    83     system("pause");
    84     return 0;
    85 }

    三.TCP的相关知识:TCP 全双工通信

    1.TCP的6个标志:发一次可以包含多个标志

    ①SYN:请求连接

    ②ACK:请求回复

    ③PSH:推送数据

    ④RST:重置连接

    ⑤FIN:结束连接

    ⑥URG:紧急指针

    2.TCP建立连接的三次握手

    ①序号和确认序号:校验包是否正确收到

    ESTablished:进入这个状态才可以进行通信

    ③TCP有重传和校验机制 不会丢包

    ④TCP接收时可能粘包:但不是所有粘包都需要处理 同种就不需要处理 只需处理不同种类的粘包(UDP就不会出现粘包的问题)

    粘包的解决:

    a.发包大小(用第一个字节) 即在包头加数据长度

    b.socket短连接

    3.TCP断开连接的四次挥手

    ①MSL:数据包最长生命周期

    在windows中为30s 在TCP文档中为2min

    在TIME_WAIT处要等2MSL(1min~·4min)的原因:

    a.保证连接正常中止

    b.允许老的重复分节在网络中消失

    4.UDP和TCP的比较:

    ①UDP中:

    当发送缓冲区<接受缓冲区:正常发送

    当发送缓冲区>接受缓冲区:丢

    TCP中:

    当发送缓冲区<接受缓冲区:正常发送

    当发送缓冲区>接受缓冲区:分片发送 不会产生丢数据的现象

    ②特点:

    UDP:

    a.面向无连接:广播 组播→1对多

    b.数据报文

    c.效率高

    d.丢包→重传 乱序→序号标识

    TCP:

    a.面向连接:3握4挥→1对1

    b.数据流:粘包 可拆

    c.重传和校验:拥塞控制 流量控制→滑动窗口

    5.慢开始与拥塞避免

    ①发送方维持一个叫拥塞窗口cwnd的状态变量:每收到一个ACK就+1

    ②当cwnd>ssthresh的时候进入拥塞避免:每经过一个RTT往返时间cwnd就+1

    ③当发送方判断网络出现拥塞:把慢开始门限设置为出现拥塞时发送窗口大小的一半 然后把拥塞窗口设置为1 执行慢开始算法

    6.快重传和快恢复

    ①快重传:

    当接收方在收到一个失序的报文段后就立即发出重复确认

    当发送方收到连续三个重复确认ACK就立即传送对方尚未收到的报文段

    ②快恢复:

    当发送方收到连续三个重复确认ACKssthresh为窗口cwnd的一半

    cwnd设置为门限ssthresh大小(或门限ssthresh+3) 执行拥塞避免

    注:如果有丢包 但是没有收到3个重复确认的ACK

    比如说只收到两个 因为剩余只有两个包未发送 那么也认为发生了拥塞

    将cwnd设为1开始慢启动 新门限设置为拥塞时门限的一半

    这说明快重传和快恢复一定是在收到三个连续重复ACK的时候才执行的!

  • 相关阅读:
    消息中间件(一)MQ详解及四大MQ比较
    WebSocket 详解教程
    Nginx 简易教程
    排序七 归并排序
    排序五 简单选择排序
    排序四 希尔排序
    排序二 快速排序
    排序一 冒泡排序
    [算法题] 人民币大小写转换(阿拉伯数字和汉字转换)
    Linux编程 18 安装软件程序(yum工具对软件包安装,删除,更新介绍)
  • 原文地址:https://www.cnblogs.com/Aaaaaalei0612/p/9448381.html
Copyright © 2011-2022 走看看