ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

网络套接字(Udp与Tcp应用)

2021-05-24 09:30:54  阅读:157  来源: 互联网

标签:Udp int sock Tcp 进程 接字 include port 端口号


目录

在网络通信中,凡是我们所写的代码,采用的接口都是系统调用接口,编写的程序都叫用户层程序,我们接下来的工作就是在用户层自定义协议。在网络模型中就是应用层,那么就是要使用传输层的接口(但是有原始套接字可以绕过传输层)

1. 认识套接字

1.1 IP

在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址。
有了IP地址能够把消息发送到对方的机器上,但是跨网络传输还需要有一个其他的标识来区分出, 这个数据要给对方的哪个程序进行解析。
即IP在公网当中全网标识一台主机,发送的时候,不仅需要目的IP,通信也要自己的源IP也发过去,因为对方主机还要对你做出“回应”。

在你打开网页,访问百度的时候,实际上硬件只是一个载体,实际上通信的是你笔记本上的软件(浏览器进程),和对方服务器上的软件(服务器进程)。更准确的一点说,实际上是运行起来的进程进行通信,所以套接字的本质就是跨网络的进程间通信。

1.2 端口号

一个笔记本上,有很多进程,所有的进程并发的进行运行。所以通信的时候还需要一个东西来标识某个进程,标定进程的方式叫端口号。

  • 端口号是一个2字节16位的整数;
  • 端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;
  • IP地址 + 端口号能够标识网络上的某一台主机的某一个进程;
  • 一个端口号只能被一个进程占用
    传输层协议(TCP和UDP)的数据段中有两个端口号, 分别叫做源端口号和目的端口号. 就是在描述 “数据是谁发的, 要发给谁”;就像你到了那台主机之还要根据目的端口号找到对应进程

1.3 套接字

IP标记某个全网唯一主机。
端口号标识主机内为一进程。那么IP+端口号就实现了标识全网内的唯一进程。而这个IP+端口号就是套接字。
在这里插入图片描述

服务器几乎永远不会关机,只会不断更新。虽然这里只简单的花了两个进程。但是这两台主机中充斥着大量的进程。公网IP保证了主机的唯一性,端口号保证了进程的唯一性。进程间通信,不同的进程看到了同一套资源,而跨网络进程通信,不同主机的进程就看到的是网络这个资源。

网络之中充斥着大量的套接字就要被管理起来
在这里插入图片描述
这里面有一个熟悉的file而file中存在一个
在这里插入图片描述
又指向这个socket指针
在这里插入图片描述
ops指针中存在着各种函数指针
在这里插入图片描述

1.4 端口号和进程id

pid表示唯一一个进程,并不是所有的进程都需要端口号,但是所有的进程在系统层面上都有一个pid。只有你这个进程是网络进程时才需要端口号。
一个进程可以绑定多个端口号
一个端口号只能用于一个进程

最开始收到数据的一定是计算机当中的网卡,然后自底向上交付。

1.5 认识TCP协议

  • 传输层协议
  • 有连接
  • 可靠传输(要保证处理数据,丢包,等等,比较复杂)
  • 面向字节流
    管道也是面向字节流的。

1.6 认识UDP协议

  • 传输层协议
  • 无连接
  • 不可靠传输
  • 面向数据报

1.7 网络字节序

低字节位在低地址处,叫做小端。
高字节位在低地址处,叫做大端。
假如你发数据,对方服务器可不知道你的数据你发的数据是大端还是小端,假如你的笔记本是小端,对方服务器是大端,那么服务器就会数据理解错误,这种情况肯定是存在,而且要被解决的。
网络规定,网络上跑的数据默认大端。假如你是小端机操作系统就会默认转为大端,收方默认接受的就是大端数据。

假设要发送0x1234abcd

在这里插入图片描述

  • TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.
  • 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;
  • 如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可;
    大端发送很方便,由于首先收到的就是高权值数据,所以就可以边计算便接收

1.8 库函数

大端就不做任何转换,小端机调用这些函数,将数据转换成大端序列。
在这里插入图片描述
这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。
例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址(点分十进制,四个.,一个点隔开一个字节,每个范围为0-255)转换后准备发送

1.9 地址转换函数

在这里插入图片描述

1.10 socket 常见API

  1. 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);

domain代表域,即使用TCP或者UDP
在这里插入图片描述

套接字类别,流式套接字,数据报套接字,原始套接字
在这里插入图片描述

协议,操作系统使用默认行为

在这里插入图片描述

最重要的是返回值
在这里插入图片描述
可以这么理解,网卡也是一种文件,通信之前需要将文件打开,这里的socket函数等价于open,返回值等价一个文件描述符。

  1. 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);

关联IP,端口号。服务器一般不发消息,永远是被动的,即绑定的,IP,端口号是客户端自己的。在系统方面表明,将IP信息与网络信息关联起来。

  • 描述符
  • 将IP地址,端口号,填进去强转之后的结构体,然后绑定。
  • 结构体长度
  1. 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
  • 文件描述符
  • 由于是面向连接的,所以需要一个等待队列,backlog代表底层连接的长度,一般不要设置太大
  1. 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);
  • 参数socket用于接收到链接请求(唯一一个),返回值socket用于通信(多个)
  1. 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

1.11 sockaddr结构

socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、 IPv6,以及UNIX DomainSocket. 然而, 各种网络协议的地址格式并不相同,操作系统实现了一种套接字接口,来解决不同套接字的编写,调用。
他就是sockaddr结构,就是用于将我们的IP,端口号等填入结构体,发给别人
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
in_addr用来表示一个IPv4的IP地址. 其实就是一个32位的整数
在这里插入图片描述

虽然socket api的接口是sockaddr, 但是我们真正在基于IPv4编程时, 使用的数据结构是sockaddr_in; 这个结构里主要有三部分信息: 地址类型, 端口号, IP地址

  • IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16位端口号和32位IP地址.
  • IPv4、 IPv6地址类型分别定义为常数AF_INET、 AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,
  • 不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容.
  • socket API中的函数形参,可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是多态,即程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数。那么强转后,在函数内怎么区分呢?由于每个字段都是16位,把他们提取出来,用if判断类型。就好了

在这里插入图片描述

2. Udp服务器

2.1 收发接口

服务器被动的收发数据,所需要接口。

收数据

在这里插入图片描述

  • 文件描述符
  • buf缓冲区
  • 期望读的长度
  • flags,读取条件是否成立
  • 输出型参数,传入方信息
  • 既做输入又做输出,输入代表结构体大小,输出代表读取结构体大小

发数据
在这里插入图片描述

  • 文件描述符
  • 发送缓冲区
  • 期望发的长度
  • 读取条件是否成立
  • 刚才收数据收到了对方的信息
  • 输入代表结构体大小,输出代表读取大小

2.2 udp服务器实现

实际上这里的ip,可以不用输入,直接在填充的时候选择INADDR_ANY,这样在客户端输入任意IP,输入端口号,都可以访问服务器。

#pragma once 

#include<iostream>
#include<stdlib.h>
#include<string>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
using namespace std;

class udpServer
{
  private:
    string ip;
    int port;

    int sock;
  public:
    udpServer(string _ip="127.0.0.1",int _port=8080)
       :ip(_ip)
       ,port(_port)
    {}
    void initServer()
    {
      //创建socket描述符,默认为3
      sock=socket(AF_INET,SOCK_DGRAM,0);
      cout<<"sock:"<<sock<<endl;
      //填充信息到sockaddr _in中
      struct sockaddr_in local;
      local.sin_family=AF_INET;
      //转成大端
      local.sin_port=htons(port);
      //sockaddr中有一个sin_addr结构体,结构体中的saddr为ip
      //将ip转为char*
      local.sin_addr.s_addr=inet_addr(ip.c_str());


      //绑定端口号
      //可以让不同类型套接字,使用同一套接口,所以要强转
      //为什么不用void*呢,套接字出现较早,void*还没定义。需要向前兼容,不能修改。
      if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
      {
        cerr<<"bind error!\n"<<endl;
        exit(1);
      }
    }  
      void strat()
      {
        char msg[64]={0};
        for(;;)
        {
          //远端的信息
          
          struct sockaddr_in end_point;
          socklen_t len=sizeof(end_point);
          
          //从网络接收数据,然后打印,拼凑一下返回给服务端
          ssize_t s=recvfrom(sock,msg,sizeof(msg)-1,0,(struct sockaddr*)&end_point,&len);
          if(s>0)
          {
            msg[s]='\0';
            cout<<"client##"<<msg<<endl;
            string echo_string=msg;
            echo_string+="[注:服务器回显]";
            sendto(sock,echo_string.c_str(),echo_string.size(),0,(struct sockaddr*)&end_point,len);

          }

        }
      }
      

    
    ~udpServer()
    {
      close(sock);
    }
};

main函数只需要简单的启动即可

#include"udpServer.hpp"

int main()
{
  udpServer *up=new udpServer;
  up->initServer();
  up->strat();
  delete up;
  return 0;
}

由于此时还没有客户端,那么怎么看到他运行起来了呢
用netstat -nlup命令,其中u代表udp,假如是 -bltp就是tcp。
在这里插入图片描述
服务端已启动。

3. udp客户端实现

#pragma once 

#include<iostream>
#include<string>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
using namespace std;

class udpClient
{
  private:
    string ip;
    int port;

    int sock;
  public:
    //连接服务器,服务器ip,port。
    udpClient(string _ip="127.0.0.1",int _port=8080)
       :ip(_ip)
       ,port(_port)
    {}
    void initClient()
    {
      //创建socket描述符,默认为3
      sock=socket(AF_INET,SOCK_DGRAM,0);
      cout<<"sock:"<<sock<<endl;
      
      //客户端不需要绑定
      //填充信息到sockaddr _in中
      //struct sockaddr_in local;
      //local.sin_family=AF_INET;
      //转成大端
      //local.sin_port=htons(port);
      //sockaddr中有一个sin_addr结构体,结构体中的saddr为ip
      //将ip转为char*
      //local.sin_addr.s_addr=inet_addr(ip.c_str());


      //绑定端口号
      //可以让不同类型套接字,使用同一套接口,所以要强转
      //为什么不用void*呢,套接字出现较早,void*还没定义。需要向前兼容,不能修改。
     // if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
    // {
       // cerr<<"bind error!\n"<<endl;
       // _exit(1);
      //}
    }  
      void strat()
      {

          string msg;
          struct sockaddr_in peer;
          peer.sin_family=AF_INET;
          peer.sin_port=htons(port);
          //点分十进制转成4字节,主机序列转成网络序列
          peer.sin_addr.s_addr=inet_addr(ip.c_str());
        for(;;)
        {

          cout<<"请输入"<<endl;
          cin>>msg;
          if(msg=="quit")
          {
            break;
          }
         //发去服务器
          sendto(sock,msg.c_str(),msg.size(),0,(struct sockaddr*)&peer,sizeof(peer));
          char echo[128];
          ssize_t s=recvfrom(sock,echo,sizeof(echo)-1,0,nullptr,nullptr);
          
          if(s>0)
          {
            echo[s]='\0';
            cout<<"server###"<<echo<<endl;
          }

        }
      }
      

    
    ~udpClient()
    {
      close(sock);
    }
};

main中初始化,然后启动

#include"udpClient.hpp"

int main()
{
  udpClient uc;
  uc.initClient();
  uc.strat();
  return 0;
}

这里提到客户端不需要自己绑定,但是为什么服务器就需要绑定呢?
首先因为一个服务器的ip,port,是众所周知的,就比如http所对应80,https对应443,ssh对应22,mysql对应3306。一个服务器,面向数不清的客户端,一经更改,客户端就找不到服务器了。客户端不需要bind,客户端并不是只有一种,比如一个手机有微信,有qq,各种客户端进程,对应着不同的服务端,假如一个客户端进程绑定着1,2,3,4端口号,同时进来另一个客户端进程需要绑定1,2,3,4.由于一个端口号只能被一个进程绑定,那么就会导致冲突,客户端无法启动。服务器会有冲突问题吗,显然是会的,但是这个服务对应的端口号比如说,80我们就会想到http,那我们在编写程序就不会把80绑给我们的进程。
客户端的端口虽然对应唯一性,但是不需要明确必须是那个端口号。因为他需要IP和Port,让UDP客户端收数据,发送数据。系统会自动进行IP和端口号绑定。

3.1 实验现象

在这里插入图片描述
客户端发数据,服务端收到,并回显到客户端。

而我们也可以,在main函数中传入参数,在命令行中带入ip与port,输入失败的时候,提示帮助手册。

在这里插入图片描述
客户端传入服务器的ip,port
在这里插入图片描述

3.2 本地环回

127.0.0.1,通常用来进行网络通信代码的本地测试,一般把网络层全部自顶向下,自底向上,跑一遍。进行测试。

4. 单进程Tcp

4.1 服务器

#ifndef __TCP__SERVER_H_
#define __TCP__SERVER_H_


#include<iostream>
#include<string>
#include<cstdlib>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<cstring>
#include<unistd.h>

using namespace std;

class tcpServer
{
  private:
    int port;
    int l_sock;
  public:
    tcpServer(int _port)
     :port(_port)
      ,l_sock(-1)
    {}
    void initServer()
    {
      l_sock=socket(AF_INET,SOCK_STREAM,0);
      if(l_sock<0)
      {
        cerr<<"socket error"<<endl;
        exit(2);
      }
      struct sockaddr_in local;
      local.sin_family=AF_INET;
      local.sin_port=htons(port);
      local.sin_addr.s_addr=INADDR_ANY;

      if(bind(l_sock,(struct sockaddr*)&local,sizeof(local))<0)
      {
           cerr<<"bind error"<<endl;
           exit(3);
      }
      if(listen(l_sock,5)<0)
      {
          cerr<<"bind error"<<endl;
          exit(4);
      }
    }
    void service(int sock)
    {
      while(true)
      {
        //读取甚至可以用read
        //udp用recvfrom,tcp用recv
        //写可以用write
        //udp用sendto,tcp用send
        char buffer[24]={0};
        size_t s=recv(sock,buffer,sizeof(buffer)-1,0);
        if(s>0)
        {
          buffer[s]={0};
          cout<<"client#: "<<buffer<<endl;

          send(sock,buffer,strlen(buffer),0);
        }
        //不写这句他就会阻塞在send或recv,写上,当s==0时就退出
        else if(s==0)
        {
              cout<<"client quit"<<endl;
              close(sock);
              break;
        }
        else{
         cout<<"recv client data error"<<endl;
         break;
        }
      }
      close(sock);
      
    }
    void start()
    {
      sockaddr_in endpoint;
      while(true)
      {
        //重新获取一个socket,加上原来的此时共有两个
        socklen_t len=sizeof(endpoint);
        int sock=accept(l_sock,(struct sockaddr*)&endpoint,&len);
        if(sock<0)
        {
          cerr<<"accept error"<<endl;
          continue;
        }
        cout<<"get a new link"<<endl;
        //当客户端退出,service也应该退出
         service(sock);
      }
    }
    ~tcpServer()
    {
      close(sock);
    }

};



#endif 

全0表示任意IP都可以。
在这里插入图片描述
虽然没有客户端,但是远程登录工具可以登录服务器
在这里插入图片描述
在这里插入图片描述
也可以进行通信
在这里插入图片描述

4.2 客户端

#include<iostream>
#include<string>
#include<cstdlib>
#include<cstring>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>


using namespace std;


class tcpClient{
  private:
    int svr_port;
    string svr_ip;
    int sock;
  public:
    tcpClient(string _ip="127.0.0.1",int port=8080)
    :svr_port(port)
     ,svr_ip(_ip)
    {}
    void initClient()
    {
     sock=socket(AF_INET,SOCK_STREAM,0);
     if(sock<0)
     {
       cerr<<"sock error"<<endl;
       exit(2);
     }
     struct sockaddr_in svr;
     svr.sin_family=AF_INET;
     svr.sin_port=htons(svr_port);
     //点分十进制-》主机序列-》网络序列
     svr.sin_addr.s_addr=inet_addr(svr_ip.c_str());

     if(connect(sock,(struct sockaddr*)&svr,sizeof(svr))!=0)
     {
       cerr<<"connect error"<<endl;
     }
    }
    void start()
    {
      char msg[64];
      while(true)
      {
        size_t s=read(0,msg,sizeof(msg)-1);
        if(s>0)
        {
           msg[s-1]=0;
           send(sock,msg,strlen(msg),0);
           size_t ss=recv(sock,msg,sizeof(msg)-1,0);
           if(ss>0)
           {
              msg[ss]=0;
              cout<<"server echo##"<<msg<<endl;
           }
        }
      }
    }
    ~tcpClient()
    {
   close(sock);
    }
};
  




#endif 

但是这个单进程版本,也就意味着当前进程不退出,别的进程就不能再次绑定。

Tcp套接字通信就像管道一样,管道也是流式服务

5. 多进程Tcp

5.1 服务器

#ifndef __TCP__SERVER_H_
#define __TCP__SERVER_H_


#include<iostream>
#include<string>
#include<cstdlib>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<cstring>
#include<unistd.h>
#include<signal.h>
using namespace std;

class tcpServer
{
  private:
    int port;
    int l_sock;
  public:
    tcpServer(int _port)
     :port(_port)
      ,l_sock(-1)
    {}
    void initServer()
    {
      signal(SIGCHLD,SIG_IGN);
      l_sock=socket(AF_INET,SOCK_STREAM,0);
      if(l_sock<0)
      {
        cerr<<"socket error"<<endl;
        exit(2);
      }
      struct sockaddr_in local;
      local.sin_family=AF_INET;
      local.sin_port=htons(port);
      local.sin_addr.s_addr=INADDR_ANY;

      if(bind(l_sock,(struct sockaddr*)&local,sizeof(local))<0)
      {
           cerr<<"bind error"<<endl;
           exit(3);
      }
      if(listen(l_sock,5)<0)
      {
          cerr<<"bind error"<<endl;
          exit(4);
      }
    }
    void service(int sock)
    {
      while(true)
      {
        //读取甚至可以用read
        //udp用recvfrom,tcp用recv
        //写可以用write
        //udp用sendto,tcp用send
        char buffer[24]={0};
        size_t s=recv(sock,buffer,sizeof(buffer)-1,0);
        if(s>0)
        {
          buffer[s]={0};
          cout<<"client#: "<<buffer<<endl;

          send(sock,buffer,strlen(buffer),0);
        }
        //不写这句他就会阻塞在send或recv,写上,当s==0时就退出
        else if(s==0)
        {
              cout<<"client quit"<<endl;
              close(sock);
              break;
        }
        else{
         cout<<"recv client data error"<<endl;
         break;
        }
      }
      close(sock);
      
    }
    void start()
    {
      sockaddr_in endpoint;
      while(true)
      {
        //重新获取一个socket,加上原来的此时共有两个
        socklen_t len=sizeof(endpoint);
        int sock=accept(l_sock,(struct sockaddr*)&endpoint,&len);
        if(sock<0)
        {
          cerr<<"accept error"<<endl;
          continue;
        }
        string cli_info=inet_ntoa(endpoint.sin_addr);
        cli_info+=":";
        cli_info+=to_string(ntohs(endpoint.sin_port));
        cout<<"get a new link"<<" "<<cli_info<<endl;


        //当客户端退出,service也应该退出
        
        pid_t id =fork();
        if(id==0)
        {
          //子进程关闭与否不影响
        close(l_sock);
         service(sock);
         exit(0);
        }
        //1. waitpid(id,NULL,0),父进程阻塞了,所以可以设置为非阻塞
        //2. 捕捉sigchild信号
        //3. 忽略sigchild信号,自动由系统回收
        //父进程必须关闭
        //父进程不断获取链接,被子进程继承下去文件描述符很多,父进程可能就会不够用
        close(sock);
    }
    }
    ~tcpServer()
    {
      close(l_sock);
    }


};



#endif 

#include"tcpServer.hpp"

static void Usages(const string& str)
{
  cout<<"Usage: port is "<<str<<endl;
}

int main(int argc,char* argv[])
{
  if(argc!=2)
  {
     Usages(argv[0]);
     exit(1);
  }
  tcpServer* tp=new tcpServer(atoi(argv[1]));
  tp->initServer();
  tp->start();
  delete tp;
  return 0;
}


5.2 客户端

#ifndef __TCP__CLIENT_H_
#define __TCP__CLIENT_H_


#include<iostream>
#include<string>
#include<cstdlib>
#include<cstring>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>


using namespace std;


class tcpClient{
  private:
    int svr_port;
    string svr_ip;
    int sock;
  public:
    tcpClient(string _ip="127.0.0.1",int port=8080)
    :svr_port(port)
     ,svr_ip(_ip)
    {}
    void initClient()
    {
     sock=socket(AF_INET,SOCK_STREAM,0);
     if(sock<0)
     {
       cerr<<"sock error"<<endl;
       exit(2);
     }
     struct sockaddr_in svr;
     svr.sin_family=AF_INET;
     svr.sin_port=htons(svr_port);
     //点分十进制-》主机序列-》网络序列
     svr.sin_addr.s_addr=inet_addr(svr_ip.c_str());

     if(connect(sock,(struct sockaddr*)&svr,sizeof(svr))!=0)
     {
       cerr<<"connect error"<<endl;
     }
    }
    void start()
    {
      char msg[64];
      while(true)
      {
        cout<<"pleease enter"<<endl;
        size_t s=read(0,msg,sizeof(msg)-1);
        if(s>0)
        {
           msg[s-1]=0;
           send(sock,msg,strlen(msg),0);
           size_t ss=recv(sock,msg,sizeof(msg)-1,0);
           if(ss>0)
           {
              msg[ss]=0;
              cout<<"server echo##"<<msg<<endl;
           }
        }
      }
    }
    ~tcpClient()
    {
   close(sock);
    }
};
  




#endif 
#include"tcpClient.hpp"

static void Usages(const string& str)
{
  cout<<"Usage: port is "<<str<<endl;
  exit(0);
}

int main(int argc,char* argv[])
{
  if(argc!=3)
  {
     Usages(argv[0]);
  }
  tcpClient* tp=new tcpClient(argv[1],atoi(argv[2]));
  tp->initClient();
  tp->start();
  delete tp;
  return 0;
}

标签:Udp,int,sock,Tcp,进程,接字,include,port,端口号
来源: https://blog.csdn.net/qq_45928272/article/details/116859986

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有