【网络编程】简单的服务端客户端实现

3

补发:2021-11-14 **

网络编程


有些图片来源——https://blog.csdn.net/TT_love9527

其他图片来源未知,侵删。


OSI模型

发送方在一层一层的打包,接受方,一层一层解包,拿到数据。

image-20211113114043879

我们要做的只是使用打包好的API函数,传递参数即可。

TCP/IP模型

可以理解为OSI七层模型的简化版本。

对比

image-20211113114251036


image-20211113114406218

收发过程可以想象成收发快递。

image-20211113114519988

每层只做它应该做的事,其余的它都不知道。

上层调用下层服务。

经典的分层模型。

双方遵守协议的内容,正确完成通信。

网络套接字编程

对比

image-20211113114946319

TCP套接字

image-20211113115130159

无论客户端还是服务端在发送的时候都多发送1个长度,字符串结束符。

TCP套接字服务端

#include<WinSock2.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")

int main(void)
{
    //初始化套接字库
    WORD wVersion;
    WSADATA wsaData;
    int err;
    wVersion = MAKEWORD(1, 1);
    err = WSAStartup(wVersion, &wsaData);//初始化哪个版本的网络库,并且将数据存放到哪里
    if (err)
    {
        return err;
    }
    if (LOBYTE(wsaData.wVersion) != 1  || HIBYTE(wsaData.wVersion) != 1)//版本检查
    {
        WSACleanup();//清理套接字库
        return -1;
    }
    //创建套接字
    SOCKET sockServer = socket(AF_INET, SOCK_STREAM, 0);  //协议族、协议栈
    //准备绑定的信息
    SOCKADDR_IN addrServer;
    addrServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//htonl——
    addrServer.sin_family = AF_INET;//协议栈
    addrServer.sin_port = htons(6000);//端口-1024以下的端口是系统保留的,htons——大小端转换,x86小端,网络传输-大端
    //绑定到本机
    bind(sockServer,(SOCKADDR*)&addrServer,sizeof(SOCKADDR));
    //监听
    std::cout << "Server start at port 6000" << std::endl;
    listen(sockServer,10);
    SOCKADDR_IN addrClient;
    int len = sizeof(SOCKADDR);
    char recvBuf[100];//创建两个缓冲区
    char sendBuf[100];
    while (1)
    {
        //接收连接请求,返回根据客户端的套接字
        SOCKET sockConnect = accept(sockServer,(SOCKADDR*)&addrClient,&len);
        sprintf_s(sendBuf,100,"hello client");
        //发
        send(sockConnect, sendBuf, strlen(sendBuf)+1,0);
         //收
        recv(sockConnect, recvBuf, 100, 0);
        std::cout << recvBuf << std::endl;
        closesocket(sockConnect); 
    }
    //关闭套接字
    closesocket(sockServer);
    //清理套接字库
    WSACleanup();
    return 0;
}

TCP套接字客户端

#include<iostream>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

int main(void)
{
    //初始化套接字库
    WORD wVersion;
    WSADATA wsaData;
    int err;
    wVersion = MAKEWORD(1, 1);
    err = WSAStartup(wVersion, &wsaData);//初始化哪个版本的网络库,并且将数据存放到哪里
    if (err)
    {
        return err;
    }
    if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)//版本检查
    {
        WSACleanup();//清理套接字库
        return -1;
    }
    //创建TCP套接字
    SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
    //绑定
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    addrSrv.sin_port = htons(6000);//与服务器绑定端口保持一致,否则无法连接
    addrSrv.sin_family = AF_INET;
    //连接
    connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
    //缓冲区
    char sendBuf[] = "hello server";
    char recvBuf[100];
    //发送数据到服务器
    send(sockClient, sendBuf, strlen(sendBuf)+1, 0);
    //接收数据
    recv(sockClient, recvBuf, 100, 0);
    std::cout << recvBuf << std::endl;  
    //关闭清理
    closesocket(sockClient);
    WSACleanup();
   // system("pause");
    return 0;
}

UDP套接字

image-20211113203130824

UDP套接字不需要监听、建立链接,绑上网卡和端口,直接发送就可以。

UDP套接字服务端

#include<iostream>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib")

int main(void)
{
    //初始化套接字库
    WORD wVersion;
    WSADATA wsaData;
    int err;
    wVersion = MAKEWORD(1, 1);
    err = WSAStartup(wVersion, &wsaData);
    if (err)
    {
        return err;
    }
    if (HIBYTE(wsaData.wVersion) != 1 || LOBYTE(wsaData.wVersion) != 1)
    {
        WSACleanup();
        return -1;
    }
    //创建套接字
    SOCKET sockServer = socket(AF_INET,SOCK_DGRAM,0);
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//主机上任何一个网卡
    addrSrv.sin_port = htons(6002);
    addrSrv.sin_family = AF_INET;
    //绑定到本机6002端口
    bind(sockServer,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
    //接收请求, 处理请求
    SOCKADDR_IN addrClient;
    int len = sizeof(SOCKADDR);
    char sendBuf[] = "hello client";
    char recvBuf[100];
    std::cout << "Start UDP Server at port 6002" << std::endl;
    while (1)
    {
        //接收数据
        recvfrom(sockServer,recvBuf,100,0,(SOCKADDR*)&addrClient,&len);
        std::cout <<"Recv:"<< recvBuf << std::endl;
        //发送数据
        sendto(sockServer, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&addrClient, len);
        std::cout << "Send:" << sendBuf << std::endl;
    }

    return 0;
}

UDP套接字客户端

#include<iostream>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib")

int main(void)
{
    //初始化套接字库
    WORD wVersion;
    WSADATA wsaData;
    int err;
    wVersion = MAKEWORD(1, 1);
    err = WSAStartup(wVersion, &wsaData);
    if (err)
    {
        return err;
    }
    if (HIBYTE(wsaData.wVersion) != 1 || LOBYTE(wsaData.wVersion) != 1)
    {
        WSACleanup();
        return -1;
    }
    //创建UDP套接字
    SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, 0);

    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    addrSrv.sin_port = htons(6002);
    addrSrv.sin_family = AF_INET;

    int len = sizeof(SOCKADDR);
    //缓冲区
    char sendBuf[] = "hello Server :)";
    char recvBuf[100];
    std::cout << "send to Server:" << sendBuf<<std::endl;
    sendto(sockClient, sendBuf, strlen(sendBuf) + 1,0,(SOCKADDR*)&addrSrv,len);
    recvfrom(sockClient, recvBuf, 100, 0,(SOCKADDR*)&addrSrv, &len);
    std::cout << "recv from Server:" << recvBuf << std::endl;
    closesocket(sockClient);
    WSACleanup();
    return 0;
}