网络基础Socket

Socket

目录

  • 目录
  • 编辑信息
  • 说明
  • 笔记
  • 函数更新
  • 参考

编辑信息

Author:chemoontheshy

Create time:2021/07/09

End time:2021/07/09

说明

本文为socket基本知识。主要window系统。

笔记

基础名词:

  • IP地址:(IP Adrress)

  • 端口:Port

  • 协议(Protocol)

    • 网络通信的约定,通信的双方必须都遵守才能正常收发数据。
    • TCP、 UDP 、 IP
  • 数据传输方式

    • SOCK_STREAM

      • 表示面向连接 的数据传输方式。

      • 数据在传输过程中不会消失。

      • 数据是按照顺序传输的。

      • 数据的发送和接收不是同步的。

    • SOCK_DGRAM

      • 表示无连接的数据传输方式。
      • 强调快速传输而非传输顺序。
      • 传输的数据可能丢失也可能损毁。
      • 数据的发送和接收时同步的。
  • TCP/IP:

    • TCP:协议,全称:The Transmission Control Protocol 传输控制协议。TCP会控制你的数据按照顺序到达并且没有错误。TCP用来确保数据的正确性。
    • IP:协议,Internert Protocol 网络协议。用于控制数据如何从源头到达目的地。也就是常说的路由。
    • TCP用来确保数据的正确性。
  • 网络三要素

    • MAC
      • Media Access Control Address 媒体访问控制地址
      • LAN Address 局域网
      • Ethernet Address 以太网地址
      • Physical Address 物理地址
    • IP Internert Protocol 网络协议
    • Port

socket流程:

  1. 需要引入WinSock的动态链接库(DLL)。

    • vs2019可以在“项目--属性--链接器--输入--附加依赖项”引入Ws2_32.lib
  2. 初始化 DLL

    int main()
    {
     //初始化 DLL
     WSADATA wsaData;
     WSAtartup(MAKEWORD(2,2),wsaData);
     ...
     //终止 DLL 使用
     WSACleanup();
     return 0;
    }
    
  1. 创建套接字socket()

    /// 
    /// 创建套接字
    /// 
    /// IP地址类型;常用的有AF_INET和AF_INET6,PF_INET等价于AF_INET
    /// 数字传输方式;常用有SOCK_STREAM(流格式套接字/面向连接的套接字)和
    /// SOCK_DGRAM(数据报套接字/无连接的套接字)
    /// 传输协议;常用的有IPPROTO_TCP和IPPTOTO_UDP,分别表示TCP传输协议和UDP传输协议 由于一般能根据type来自动推断类型,故默认填写0,可以不填写参数,特殊情况不可以:有两种不同的协议支持同一种地址类型和数据类型传输类型
    /// 正常返回>0,错误返回-1(INVALID_SOCKET)
    static SOCKET creatSocket(int af, int type, int protocol=0)
    {
     SOCKET sock=socket(af,type,protocol);
        if(sock == INVALID_SOCKET)
        {
            return INVALID_SOCKET;
        }
        return sock;
    }
    
  1. 绑定端号bind()和connect()

    服务端为bind(),客服端为connect();

    /// 
    /// 将创建的套接字与IP地址、端口绑定。
    /// 
    /// 创建的套接字
    /// ip地址
    /// 端口
    /// 正常返回true,错误返回false
    bool STCP::Bind(SOCKET sock, const char* ip, uint16_t port)
    {
     sockaddr_in addr;
     addr.sin_family = AF_INET;
     addr.sin_port = htons(port);
        //INADDR_ANY 就是指地址位0.0.0.0
     addr.sin_addr.S_un.S_addr = INADDR_ANY;
     if (bind(sock, reinterpret_cast(&addr), sizeof(addr)) == SOCKET_ERROR) {
         printf("TCP::bind() failed.\n");
         return false;
     }
     return true;
    
    }
    
    /// 
    /// sockaddr_in结构体
    /// 
    typedef struct sockaddr_in {
        ADDRESS_FAMILY sin_family;   //地址族,地址类型
        USHORT sin_port;         //16位的端口号
        IN_ADDR sin_addr;            //32位IP地址
        CHAR sin_zero[8];            //不使用,一般填充0
    } SOCKADDR_IN, *PSOCKADDR_IN;
    /// 
    /// 将创建的套接字与IP地址、端口绑定。
    /// 
    /// 创建的套接字(文件描述符)
    /// sockaddr结构体变量的指针
    /// 端口
    /// 正常返回>0,错误返回-1(INVALID_SOCKET)
    int bind(SOCKET sock, const struct sockaddr *addr, int addrlen);  //Windows
    /// 
    /// 将创建的套接字与IP地址、端口绑定。
    /// 
    /// 创建的套接字(文件描述符)
    /// sockaddr结构体变量的指针
    /// 端口
    /// 正常返回>0,错误返回-1(INVALID_SOCKET)
    int connect(SOCKET sock, const struct sockaddr *serv_addr, int addrlen);  //Windows
    
  1. 开始监听listend()和接收数据accpet()

    对于服务端程序使用bind()绑定套接字后,还需要使用listen()函数进入被动监听状态,再调用accepet()函数就可以随时响应客户端的请求了。

    /// 
    /// 进入监听状态
    /// 
    /// 创建的套接字(文件描述符)
    /// 
    /// 端口
    /// 正常返回>0,错误返回-1(INVALID_SOCKET)
    int listen(SOCKET sock, int backlog);  //Windows
    
    /// 
    /// 进入监听状态
    /// 
    /// 创建的套接字(文件描述符)
    /// sockaddr结构体变量的指针
    /// 地址长度
    /// 正常返回>0,错误返回-1(INVALID_SOCKET)
    SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen);  //Windows
    
  1. 发送与接收

    /// TCP
    /// 
    /// 进入监听状态
    /// 
    /// 创建的套接字(文件描述符)
    /// 数据指针头
    /// 数据的长度
    /// 一般为0或者flags
    /// 正常返回>0,发送数据的长度,否则-1
    int send(SOCKET sock, const char *buf, int len, int flags); //Windows
    
    /// 
    /// 进入监听状态
    /// 
    /// 创建的套接字(文件描述符)
    /// 数据指针头
    /// 数据的长度
    /// 一般为0或者flags
    /// 正常返回>0,接收到数据的长度,否则-1
    int recv(SOCKET sock, char *buf, int len, int flags); //Windows
    
    //UDP
    /// 
    /// 发送数据
    /// 
    /// 创建的套接字(文件描述符)
    /// 保存待传输数据的缓冲区地址
    /// 带传输数据的长度(以字节计)
    /// 可选项参数,若没有可传递0
    /// 可选项参数,若没有可传递0
    /// 传递给参数 to 的地址值结构体变量的长度
    /// 正常返回>0,发送数据的长度,否则-1
    int sendto(SOCKET sock, const char *buf, int nbytes, int flags, const struct sockadr *to, int addrlen);  //Windows
    
    /// 
    /// 接收数据
    /// 
    /// 创建的套接字(文件描述符)
    /// 保存待传输数据的缓冲区地址
    /// 可接收的最大字节数(不能超过buf缓冲区的大小)
    /// 可选项参数,若没有可传递0
    /// 存有发送端地址信息的sockaddr结构体变量的地址
    /// 保存参数 from 的结构体变量长度的变量地址值
    /// 正常返回>0,接收数据的长度,否则-1
    int recvfrom(SOCKET sock, char *buf, int nbytes, int flags, const struct sockaddr *from, int *addrlen);  //Windows
    
  1. 结束

    /// 
    /// 关闭socket
    /// 
    /// 创建的套接字(文件描述符)
    closesocket(sock);
    

函数更新

//旧函数,不建议使用
//sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
//新函数
inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr);

参考

http://c.biancheng.net/cpp/html/3029.html

你可能感兴趣的:(网络基础Socket)