2021-05-17网络00
请注意,本文编写于 561 天前,最后修改于 204 天前,其中某些信息可能已经过时。

目录


一、协议

约定好的数据格式,约定好的数据的解析格式、

分组传输,将需要在通信网中传送的信息分割成一段较短的信息单位,在每段信息加上交换时所需的呼叫控制信号和校验信息,再按规定的格式排列成一个报文分组,一个分组在网内作为一个整体传输。

ip地址和端口

IP地址
IP地址是一个32位的整数。通常为了便于表示,会将之分为四个8位的二进制整数,每个8位的二进制整数又可表示为一个0~255的十进制数字。

IP地址被分为A、B、C、D、E类:

  • A类适用大型网络,地址区间:0.0.0.0 ~ 127.255.255.255(地址最高位必须是0)
  • B类适用中型网络,地址区间:128.0.0.0 ~ 191.255.255.255(地址最高位必须为10)
  • C类适用小型网络,地址区间:192.0.0.0 ~ 223.255.255.255(地址最高位必须是110)
  • D类称为组播地址,地址区间:224.0.0.0 ~ 239.255.255.255(地址最高位必须是1110)
  • E类为保留地址,用于将来和实验用,地址区间:240.0.0.0 ~ 255.255.255.255(地址最高位必须是11110)每类IP地址中,最大的一个地址为广播地址。

IP地址按用途来分,分为公有IP和私有IP。

公有地址(Public address)由Inter NIC(Internet Network Information Center 因特网信息中心)负责。这些IP地址分配给注册并向Inter NIC提出申请的组织机构。通过它直接访问因特网。
私有地址(Private address)属于非注册地址,专门为组织机构内部使用。
以下列出留用的内部私有地址

  • A类 10.0.0.0 ~ 10.255.255.255
  • B类 172.16.0.0 ~ 172.31.255.255
  • C类 192.168.0.0 ~ 192.168.255.255

端口
端口是一个16位的整数,用于表示数据交给哪个通信程序处理。端口是应用程序与外界交流的出入口。

不同的应用程序处理不同端口上的数据,同一台机器上不能有两个程序共用一个端口。

端口号从0到65535,通常被分为3类:

  • 公认端口:从0到1023,它们紧密绑定一些服务,比如80端口被分给www服务,21端口被分给FTP服务;
  • 注册端口:从1024到49151,被分配给用户进程和应用程序。这些进程主要是用户选择安装的一些应用程序,而不是已经分配好了公认端口的常用程序;
  • 动态和/或私有端口:从49152到65535,之所以称为动态端口,是因为它 一般不固定分配某种服务,而是动态分配。动态分配是指当一个系统进程或应用 程序进程需要网络通信时,它向主机申请一个端口,主机从可用的端口号中分配 一个供它使用。当这个进程关闭时,同时也就释放了所占用的端口号。

服务器客户端 C/S 架构, 服务器通常要绑定好IP和端口,而客户端的端口可以随机。

运营商给到我们ip地址之后,别的电脑该怎么知道这个ip地址呢?
为了解决这个问题,这个电脑通信的时候会在消息中带自己的信息类似User-Agent这里就包含了,通信所需要的的信息。

  1. LAN (局域网):通常指几千米以内的,可以通过某种介质互联的计算机/ 打印机或其他设备的集合

  2. MAN(城域网):覆盖范围为中等规模,介于局域网和广域网,通常是 在一个城市内的连接(距离为10KM 左右)

  3. WAN(广域网):分布距离更远,它通过各种类型的串行连接以便在更大 的地理区域实现接入。

OSI 七层协议

七层协议
每个数据报的部分,上层的包裹是放入下层的数据中,而数据前面则是这个数据的表头。其中比较特殊的是第二层, 因为第二层 (数据链结层) 主要是位于软件封包 (packet) 以及硬件讯框 (frame) 中间的一个阶层, 他必须要将软件包装的包裹放入到硬件能够处理的包裹中,因此这个阶层又分为两个子层在处理相对应的数据。
各层所负责的工作

TCP/IP

TCP/IP

互联网协议套件(英语:Internet Protocol Suite,缩写IPS)是一个网络通信模型,以及一整个网络传输协议家族,为网际网络的基础通信架构。它常被通称为TCP/IP协议族(英语:TCP/IP ProtocolSuite,或TCP/IP Protocols),简称TCP/IP。因为该协议家族的两个核心协议:TCP(传输控制协议)和IP(网际协议),为该家族中最早通过的标准。

TCP/IP协议族

2、udp

网络编程 - socket编程 - 套接字编程, 都是一个东西。最早是在Unix上开发的,后来微软移植到了windows平台,并且在此基础上,开发了WSA
步骤:

1. 创建socket,指定使用的协议

c
SOCKET socket(
    int af,
    int type,
    int protocol
);

第一个参数:如果是ipv4:AF_INET,如果是ipv6:AF_INET6
第二个参数:
tcp:SOCK_STREAM(数据报)
udp:SOCK_DGRAM(数据流)
第三个参数:协议IPPROTO_UDPIPPROTO_TCP等等。

返回值 类似于句柄

c
# define WIN32_LEAN_AND_MEAN
# include <windows.h>    //windows.h和Winsock2.h 有重复,所以要添加# define WIN32_LEAN_AND_MEAN
# include <Winsock2.h>
# pragma comment(lib, "Ws2_32.lib")

int main()
{
    //对Ws2_32.lib做初始化
    InitWs2();

    //1) 创建socket
    SOCKET sockServer = socket(
        AF_INET, //ipv4地址簇
        SOCK_DGRAM, //数据报
        IPPROTO_UDP);//udp协议
    if (sockServer == INVALID_SOCKET)
    {
        printf("socket 创建失败 \r\n");
        return 0;
    }
    else
    {
        printf("socket 创建socket成功 \r\n");
    }
    //反初始化
    UninitWs32();
}
c
void InitWs2()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        return;
    }

    /* Confirm that the WinSock DLL supports 2.2.*/
    /* Note that if the DLL supports versions greater    */
    /* than 2.2 in addition to 2.2, it will still return */
    /* 2.2 in wVersion since that is the version we      */
    /* requested.                                        */

    if (LOBYTE(wsaData.wVersion) != 2 ||
        HIBYTE(wsaData.wVersion) != 2) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        WSACleanup();
        return;
    }

    /* The WinSock DLL is acceptable. Proceed. */
}

void UninitWs32()
{
    WSACleanup();
}

2. 绑定端口

c
int bind(
    SOCKET s,
    const struct sockaddr FAR *name,
    int namelen
);

第一个参数:是socket 就是上面创建的
第二个参数:是一个结构体
第三个参数:结构体的长度

这个结构体:

c
struct sockaddr {
  u_short    sa_family;
  char       sa_data[14];
};

很显然这个结构体不好用,所以换一个:

c
struct sockaddr_in {
        short   sin_family;
        u_short sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
};
c
 //绑定端口 127.0.0.1 回环地址
    sockaddr_in siServer;
    siServer.sin_family = AF_INET;
    siServer.sin_port = htons(0x9527);//小尾转大尾 host to net short ntoh
    siServer.sin_addr.S_un.S_addr =
        //0x0100007f;//大尾
        inet_addr("127.0.0.1");
        //0x7f000001;
    int nRet = bind(sockServer, (sockaddr*)&siServer, sizeof(siServer));
    if (nRet == SOCKET_ERROR)
    {
        printf("绑定地址失败 \r\n");
        return 0;
    }
    else
    {
        printf("绑定地址成功 \r\n");
    }

3. 发送数据

c
int sendto(
    SOCKET s,
    const char FAR *buf,
    int len,
    int flags,
    const struct sockaddr FAR *to,
    int tolen
);

第一个参数,创建的socket
第二个参数:要发送数据的缓冲区
第三个参数:要发送缓冲区大小
第四个参数:标志
第五个参数:发给谁
第六个参数:发给谁大小

c
 //发送数据
    sockaddr_in siServer;
    siServer.sin_family = AF_INET;
    siServer.sin_port = htons(0x9527);//小尾转大尾 host to net short ntoh
    siServer.sin_addr.S_un.S_addr =
        //0x0100007f;//大尾
        inet_addr("127.0.0.1");
    char szBuff[] = { "hello socket" };
    int nRet = sendto(sockClient,
        szBuff, sizeof(szBuff),
        0,
        (sockaddr*)&siServer, sizeof(siServer));
    if (nRet == SOCKET_ERROR)
    {
        printf("发送数据失败 \r\n");
    }
    else
    {
        printf("发送数据完毕 \r\n");
    }

4. 接受数据

c
int recvfrom(
    SOCKET s,
    char FAR* buf,
    int len,
    int flags,
    struct sockaddr FAR *from,
    int FAR *fromlen
);

第一个参数:句柄
第二个参数:接受字符的缓冲区
第三个参数:缓冲区大小
第四个参数:标志,填0
第五个参数:发送数据的地址

c
 //收数据
    sockaddr_in siClient = {0};
    int nLen = sizeof(siClient);
    char szBuff[MAXBYTE] = {0};
    nRet = recvfrom(sockServer, //句柄
        szBuff, sizeof(szBuff), //接受数据缓冲区
        0,//标志
        (sockaddr*)&siClient, &nLen//发送来的数据的地址
    );
    if (nRet == 0 || nRet == SOCKET_ERROR)
    {
        printf("接受数据失败\r\n");
        return 0;
    }
    else {
        printf("受到来自:%s:%d的数据:%s \r\n",
            inet_ntoa(siClient.sin_addr),
            ntohs(siClient.sin_port),
            szBuff);
    }

5. 关闭socket

c
int closesocket(
    SOCKET s
);
c
closesocket(sockServer);

server端

c
# include <iostream>
using namespace std;


# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <Winsock2.h>
# pragma comment(lib, "Ws2_32.lib")

void InitWs2();
void UninitWs32();

int main()
{
    InitWs2();

    //1) 创建socket
    SOCKET sockServer = socket(
        AF_INET, //ipv4地址簇
        SOCK_DGRAM, //数据报
        IPPROTO_UDP);//udp协议
    if (sockServer == INVALID_SOCKET)
    {
        printf("socket 创建失败 \r\n");
        return 0;
    }
    else
    {
        printf("socket 创建socket成功 \r\n");
    }

    //绑定端口 127.0.0.1 回环地址  
    sockaddr_in siServer;
    siServer.sin_family = AF_INET;
    siServer.sin_port = htons(0x9527);//小尾转大尾 host to net short ntoh
    siServer.sin_addr.S_un.S_addr =
        //0x0100007f;//大尾
        inet_addr("127.0.0.1");
        //0x7f000001;
    int nRet = bind(sockServer, (sockaddr*)&siServer, sizeof(siServer));
    if (nRet == SOCKET_ERROR)
    {
        printf("绑定地址失败 \r\n");
        return 0;
    }
    else
    {
        printf("绑定地址成功 \r\n");
    }

    //收数据
    sockaddr_in siClient = {0};
    int nLen = sizeof(siClient);
    char szBuff[MAXBYTE] = {0};
    nRet = recvfrom(sockServer, //句柄
        szBuff, sizeof(szBuff), //接受数据缓冲区
        0,//标志
        (sockaddr*)&siClient, &nLen//发送来的数据的地址
       
    );
    if (nRet == 0 || nRet == SOCKET_ERROR)
    {
        printf("接受数据失败\r\n");
        return 0;
    }
    else {
        printf("受到来自:%s:%d的数据:%s \r\n",
            inet_ntoa(siClient.sin_addr),
            ntohs(siClient.sin_port),
            szBuff);
    }

    char szSend[] = {"recv OK!"};
    nRet = sendto(sockServer,
        
        szSend, sizeof(szSend),
        0,
        (sockaddr*)&siClient, sizeof(siClient));
    if (nRet == SOCKET_ERROR)
    {
        printf("发送数据失败 \r\n");
    }
    else
    {
        printf("回复数据到:%s:%d的数据:%s \r\n",
            inet_ntoa(siClient.sin_addr),
            ntohs(siClient.sin_port),
            szSend);
    }

    closesocket(sockServer);
    std::cout << "Hello World!\n";
}


void InitWs2()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        return;
    }

    /* Confirm that the WinSock DLL supports 2.2.*/
    /* Note that if the DLL supports versions greater    */
    /* than 2.2 in addition to 2.2, it will still return */
    /* 2.2 in wVersion since that is the version we      */
    /* requested.                                        */

    if (LOBYTE(wsaData.wVersion) != 2 ||
        HIBYTE(wsaData.wVersion) != 2) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        WSACleanup();
        return;
    }

    /* The WinSock DLL is acceptable. Proceed. */
}

void UninitWs32()
{
    WSACleanup();
}

client端

c
# include <iostream>
using namespace std;

# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <Winsock2.h>
# pragma comment(lib, "Ws2_32.lib")

void InitWs2();
void UninitWs32();


int main()
{
    InitWs2();

    //1) 创建socket
    SOCKET sockClient = socket(
        AF_INET, //ipv4地址簇
        SOCK_DGRAM, //数据报
        IPPROTO_UDP);//udp协议
    if (sockClient == INVALID_SOCKET)
    {
        printf("socket 创建失败 \r\n");
        return 0;
    }
    else
    {
        printf("socket 创建socket成功 \r\n");
    }

    //发送数据
    sockaddr_in siServer;
    siServer.sin_family = AF_INET;
    siServer.sin_port = htons(0x9527);//小尾转大尾 host to net short ntoh
    siServer.sin_addr.S_un.S_addr =
        //0x0100007f;//大尾
        inet_addr("127.0.0.1");
    char szBuff[] = { "hello socket" };
    int nRet = sendto(sockClient,
        szBuff, sizeof(szBuff),
        0,
        (sockaddr*)&siServer, sizeof(siServer));
    if (nRet == SOCKET_ERROR)
    {
        printf("发送数据失败 \r\n");
    }
    else
    {
        printf("发送数据完毕 \r\n");
    }

    sockaddr_in siRecv = { 0 };
    int nLen = sizeof(siRecv);
    char szRecv[MAXBYTE] = { 0 };
    nRet = recvfrom(sockClient, //句柄
        szRecv, sizeof(szRecv), //接受数据缓冲区
        0,//标志
        (sockaddr*)&siRecv, &nLen//发送来的数据的地址
    );
    if (nRet == 0 || nRet == SOCKET_ERROR)
    {
        printf("接受数据失败\r\n");
        return 0;
    }
    else {
        printf("受到来自:%s:%d的数据:%s \r\n",
            inet_ntoa(siRecv.sin_addr),
            ntohs(siRecv.sin_port),
            szRecv);
    }

    std::cout << "Hello World!\n";
    closesocket(sockClient);
    UninitWs32();
}


void InitWs2()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        return;
    }

    /* Confirm that the WinSock DLL supports 2.2.*/
    /* Note that if the DLL supports versions greater    */
    /* than 2.2 in addition to 2.2, it will still return */
    /* 2.2 in wVersion since that is the version we      */
    /* requested.                                        */

    if (LOBYTE(wsaData.wVersion) != 2 ||
        HIBYTE(wsaData.wVersion) != 2) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        WSACleanup();
        return;
    }

    /* The WinSock DLL is acceptable. Proceed. */
}

void UninitWs32()
{
    WSACleanup();
}

效果

计算机网络 - IP和端口
网络基础笔记——OSI七层模型

本文作者:Na1r

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!