网络编程套接字

2023-05-16

能够实现一个简单的udp客户端/服务器;
实现一个简单的tcp客户端/服务器(单连接版本, 多进程版本, 多线程版本);
套接字编程:主要讲解的就是如何编写一个网络通信程序
1.网络通信的数据中都会包含一个完整的五元组:sipsportdipdporprotocol(源端IP,源端端口,对端IP,对端端口,协议五元组完整的描述了数据从哪来,到哪去,用的是什么数据格式。
2.网络通信,通常讨论的是两个主机进程之间的通信:客户端&服务端

客户端网络通信程序:通常指的是用户使用的一端
服务端网络通信程序:通常指的是网络应用提供商提供服务的一端程序
我们后边说找工作找的后台服务器开发工作,指的是编写服务端程序的工作。
并且我们要了解:客户端永远都是首先发起请求的一端(因为服务端是不知道客户端地址的(动态地址分配技术--谁上网给谁分配地址))
但是网络应用服务提供商,开发的客户端程序中都写入了服务器端的地址和端口,因此客户端是知道服务端地址的。还有一种原因就是,只有客户发送了请求,服务端才能提供对应的服务

套接字编程:
套接字:socket的翻译,通常表示的是系统提供给程序员实现网络通信的一套接口.
因此套接字编程学习的其实就是套接字接口的使用,通过这套接口完成网络通信程序的开发我们所讲解的套接字编程,主要是两个协议的通信程序编写:传输层的TCP和UDP协议。
TCP协议和UDP协议的区别:
联系:都是传输层协议
tcp协议:传输控制协议--提供的是面向连接,可靠,基于字节流的数据传输
面向连接:通信前先要确定双方是否具有数据收发的能力

可靠传输:通过大量的一些控制机制,保证数据能够安全(有序且完整,一致)到达对端。
字节流:没有传输大小限制,传输比较灵活的一种传输方式 tcp适用于安全要求大于实时要求的场景,比如文件传输

udp协议:用户数据报协议--提供的是无连接,不可靠,基于数据包的数据传输
无连接:需要建立连接,只要知道对方的地址,就可以直接发送数据
不可靠:只要数据发送出去了就行,不管是否能够到达对端
数据报:有最大大小限制,且传输交付有大小限制的一种传输方式
因为没有大量的控制机制,因此传输速度快,因此适用于实时性要求大于安全性要求的场景,比如视频传输,音频传输。
UDP协议通信程序的编写:

接口: 

//1、创建套接字:
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
domin:地址域类型(域间通信,ipv4通信,ipv6通信.。。不同通信方式有不同的地址结构);AF_INET--IPV4地址域类型
type: 套接字类型
  SOCK_STREAM:流式套接字,提供的是字节流传输,默认协议是TCP协议
  SOCK_DGRAM:数据报套接字,提供的是数据报传输,默认协议是UDRP协议
protocol;协议类型
 IPPROTO_TCP:值为6
 IPPROTO_UDP:值为17
  返回一个套接字描述符;失败返回-1;
//2、为套接字绑定地址信息
// 绑定端口号,地址信息 (TCP/UDP, 服务器)      
int bind(int socket, const struct sockaddr *address,
         socklen_t address_len);
// 开始监听socket (TCP, 服务器)
//socket:socket返回的套接字描述符
//address 要绑定的地址信息(不同的地址域类型,有不同的地址结构)
成功返回0,失败返回-1;
//3、发送数据
ssize_t sendto(int sockfd,void*buf,size_t len,int flag, struct sockaddr *peer,socklen_t len)
/3、接收数据
 ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *peer, socklen_t *addrlen);



int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,
         socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,
         socklen_t addrlen);

 

5.关闭套接字,释放资源

int close(int fd);

 1 #include<iostream>
  2 #include<string.h>
  3 #include<arpa/inet.h>
  4 #include<netinet/in.h>
  5 #include<sys/socket.h>
  6 #include<unistd.h>
  7 #include<stdio.h>
  8 class udpsocket{
  9   private:
 10     int _socket;
 11   public:
 12     udpsocket():_socket(-1){}
 13     ~udpsocket(){
 14          Close();
 15     }
 16   public:
 17     bool Socket()//创建套接字
 18     {
 19       _socket=socket(AF_INET,SOCK_DGRAM ,IPPROTO_UDP);
 20       if(_socket<0){
 21         perror("socket error");
 22         return false;
 23       }
 24       return true;
 25     }
 26     bool Bind(const std::string &ip,uint16_t  port){
 27      struct sockaddr_in addr;
 28      addr.sin_family=AF_INET;
 29      addr.sin_port=htons(port);                                                                                                                                     
 30      addr.sin_addr.s_addr=inet_addr(ip.c_str());
 31      socklen_t len=sizeof(struct sockaddr_in);
 32      int ret =bind(_socket,(struct sockaddr*)&addr,len);
 33     if(ret<0){
 34       perror("bind error");
 35        return false;
 36     }
 37      return true;
 38     }
 39     bool Recv(std::string *body,std::string *peer_ip=NULL,uint16_t *peer_port=NULL){
 40       struct sockaddr_in peer;       
 41       char tmp[4096]={0};
 42       socklen_t len=sizeof(struct sockaddr_in);
 43       ssize_t ret=recvfrom(_socket,tmp,4096,0,(struct sockaddr*)&peer,&len);
 44       if(ret<0){
 45         perror("recvfrom error");
 46         return false;
 47       }
 48      if(peer_ip!=NULL) *peer_ip=inet_ntoa(peer.sin_addr);
 49      if(peer_port!=NULL) *peer_port=ntohs(peer.sin_port);
 50       body->assign(tmp,ret);
 51       return true;
 52     }
 53     bool Send(const std::string &body,const std::string &peer_ip,uint16_t peer_port){ 
 54      struct sockaddr_in addr;
 55      addr.sin_family=AF_INET;
 56      addr.sin_port=htons(peer_port);
 57      addr.sin_addr.s_addr=inet_addr(peer_ip.c_str());                                                                                                               
 58      socklen_t len=sizeof(struct sockaddr_in);
 59      ssize_t ret=sendto(_socket,body.c_str(),body.size(),0,(struct 
          sockaddr*)&addr,len);    
 60      if(ret<0){
 61        perror("sendto error");
 62        return false;
 63      }
 64       return true;
 65     }
 66     bool Close(){
 67     if(_socket!=-1){ 
 68      close(_socket);
 69        _socket=-1; 
 70    }
 71     return true;
 72     }
 73 };

1 #include"udp_socket.hpp"
    2 #include<assert.h>
    3 int main(int argc,char *argv[])
    4 {
    5   if(argc!=3){
    6     std::cout<<"usage: ./udp_cli 192.168.2.2 9000\n";
    7     return -1;
    8   }
    9   std::string srv_ip=argv[1];
   10   uint16_t srv_port=std::stoi(argv[2]);
   11   udpsocket cli_sock;
   12   //1、创建套接字
   13  assert(cli_sock.Socket()==true);
   14   //2、为套接字绑定地址信息
   15   //循环通信
   16  while(1){
   17   //发送数据
   18    std::string data;
   19    std::cout<<"client say: ";
   20    fflush(stdout);
   21    std::cin>>data;
   22    assert(cli_sock.Send(data,srv_ip,srv_port)==true);                                                                                                             
   23    //接收数据
   24    data.clear();
   25    assert(cli_sock.Recv(&data)==true);
   26    std::cout<<"serve say:"<<data<<std::endl;
   27  }
   28   //5、关闭套接字
   29 cli_sock.Close();
   30 
   31   return 0;
   32 }

TCP协议:

接口: 

socket():
socket() 打开一个网络通讯端口 , 如果成功的话 , 就像 open() 一样返回一个文件描述符 ;
应用程序可以像读写文件一样用 read/write 在网络上收发数据 ;
如果 socket() 调用出错则返回 -1;
对于 IPv4, family 参数指定为 AF_INET;
对于 TCP 协议 ,type 参数指定为 SOCK_STREAM, 表示面向流的传输协议
protocol 参数的介绍从略 , 指定为 0 即可
bind():
服务器程序所监听的网络地址和端口号通常是固定不变的 , 客户端程序得知服务器程序的地址和端口号后 就可以向服务器发起连接; 服务器需要调用 bind 绑定一个固定的网络地址和端口号 ;
bind() 成功返回 0, 失败返回 -1
bind() 的作用是将参数 sockfd myaddr 绑定在一起 , 使 sockfd 这个用于网络通讯的文件描述符监听
myaddr 所描述的地址和端口号 ;
struct sockaddr * 是一个通用指针类型 ,myaddr 参数实际上可以接受多种协议的 sockaddr 结 构体, 而它们的长度各不相同 , 所以需要第三个参数 addrlen 指定结构体的长度 ;
listen():
listen() 声明 sockfd 处于监听状态 , 并且最多允许有 backlog 个客户端处于连接等待状态 , 如果接收到更多 的连接请求就忽略, 这里设置不会太大 ( 一般是 5) ;
listen() 成功返回 0, 失败返回-1.
connect ():
客户端需要调用 connect() 连接服务器 ;
connect bind 的参数形式一致 , 区别在于 bind 的参数是自己的地址 , connect 的参数是对方的地址 ;
connect() 成功返回 0, 出错返回 -1;
accept():
三次握手完成后 , 服务器调用 accept() 接受连接 ;
如果服务器调用 accept() 时还没有客户端的连接请求 , 就阻塞等待直到有客户端连接上来 ;
addr 是一个传出参数 ,accept() 返回时传出客户端的地址和端口号 ;
如果给 addr 参数传 NULL, 表示不关心客户端的地址 ;
addrlen 参数是一个传入传出参数 (value-result argument), 传入的是调用者提供的 , 缓冲区 addr 的长度
以避免缓冲区溢出问题 , 传出的是客户端地址结构体的实际长度 ( 有可能没有占满调用者提供的缓冲区 );

关闭套接字,释放资源

int close(int fd);

代码示例:

//封装库
#include<iostream>
  2 #include<string>
  3 #include<cassert>
  4 #include<arpa/inet.h>
  5 #include<unistd.h>
  6 #include<netinet/in.h>
  7 #include<sys/socket.h>
  8 #include<stdio.h>
  9 int MAX_LISTEN=1024;
 10 class TcpSocket{
 11   private:
 12   int _sockfd;
 13   public:
 14   TcpSocket(): _sockfd(-1){};
 15   ~TcpSocket(){
 16    // Close();
 17   }
 18   int fd(){
 19     return _sockfd;
 20   }
 21   void set(int fd){
 22     _sockfd=fd;
 23   }
 24   bool Socket(){
 25     _sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
 26     if(_sockfd<0){
 27       perror("sockfd error");                                                                                                                                       
 28       return false;
 29     }
 30     return true;
 31   }
 32   bool Bind(const std::string &ip,uint16_t port){
 33   struct sockaddr_in addr;
 34   addr.sin_family=AF_INET;
 35   addr.sin_port=htons(port);
 36   addr.sin_addr.s_addr=inet_addr(ip.c_str());
 37   socklen_t len=sizeof(sockaddr_in);
 38   int ret=bind(_sockfd,( struct sockaddr*)&addr,len);
 39   if(ret<0){
 40     perror("bind error");
 41     return false;
 42   }
 43    return true;
 44   }
 45   bool Listen(int backlog=MAX_LISTEN)
 46   {
 47     int ret=listen(_sockfd,backlog);
 48     if(ret<0){
 49       perror("listen error");
 50       return false;
 51     }
 52       return true;
 53   }
 54   bool Connect(const std::string &srvip,uint16_t srvport){
 55       struct sockaddr_in addr;
 56       addr.sin_family=AF_INET;
 57       addr.sin_port=htons(srvport);
 58       addr.sin_addr.s_addr=inet_addr(srvip.c_str());
 59       socklen_t len=sizeof(sockaddr_in); 
 60       int ret=connect(_sockfd,(struct sockaddr*)&addr,len);
 61       if(ret<0){
 62           perror("connect error");
 63           return false;
 64       }
 65          return true;
 66 
 67   }
 68 
 69   bool Accept(TcpSocket *new_sock,std::string *cli_ip=NULL,uint16_t *cli_port=NULL){
 70    struct sockaddr_in peer;
 71    socklen_t  addrlen=sizeof(struct sockaddr_in);
 72    int newfd=accept(_sockfd,(struct sockaddr*)&peer,&addrlen);
 73    if(newfd<0){
 74      perror("accept error");
 75      return false;
 76    }
 77    new_sock->_sockfd=newfd;
 78 
 79   if(cli_ip) *cli_ip=inet_ntoa(peer.sin_addr);
 80   if(cli_port) *cli_port=ntohs(peer.sin_port);
 81   return true;
 82   }
 83 
 84   bool Send(const std::string&body){
 85       ssize_t ret=send(_sockfd,body.c_str(),body.size(),0);
 86        if(ret<0){
 87         perror("send error");
 88         return false;
 89       }
 90          return true;
 91   }
 92   bool Recv(std::string *body)
 93   {
 94       //接收数据
 95   char temp[1024]={0}; 
 96    ssize_t ret=recv(_sockfd,temp,1023,0);
 97    if(ret<0){
 98      perror("Recv error");
 99      return false;
100    }
101      else if(ret==0){
102        perror("connect break");
103        return false;
104      }
105      body->assign(temp,ret);
106      return true;
107   }
108   bool Close(){
109     if(_sockfd!=-1){
110       close(_sockfd);
111       _sockfd=-1;
112     }
113     return true;
114   }
115 
116 };
  //服务端
 #include"tcp_socket.hpp"
     int main(int agc,char *argv[])
     {
       if(agc!=3){
         printf("usage: ./tcp_srv 192.168.177.128 9000");
         return -1;
       }
       std::string ip=argv[1];
       uint16_t port=std::stoi(argv[2]);                                                                                                                               
    
      //服务器流程
      TcpSocket lsn_sock;
      //创建套接字
     assert( lsn_sock.Socket()!=false);
      //为套接字绑定地址信息
      assert(lsn_sock.Bind(ip,port));
      //开始监听
      assert(lsn_sock.Listen());
      //获取新建连接
      while(1){
       TcpSocket new_sock;
       std::string cli_ip;
       uint16_t cli_port;
       bool ret=lsn_sock.Accept(&new_sock,&cli_ip,&cli_port);
       if(ret==false){
         continue;
      }
       std::cout<<"new client:"<<cli_ip<<":"<<cli_ip<<std::endl;
       //使用新建连接发送数据 
       std::string buf; 
        ret=new_sock.Recv(&buf);
        if(ret==false){
         new_sock.Close();
          continue;
            }
          std::cout<<cli_ip<<":"<<cli_port<<"say"<<buf<<std::endl;
         buf.clear();
         std::cout<<"serve say";
         fflush(stdout);
         std::cin>>buf;
         new_sock.Send(buf);
       if(ret==false){
           new_sock.Close();
           continue;
        }
      }
     //关闭套接字
      lsn_sock.Close();
     return 0;
    }

 //客户端  
    #include"tcp_socket.hpp"
    2 
    3 int main(int argc,char *argv[])
    4 {
    5   if(argc!=3){
    6     printf("usage: ./tcp_srv 192.168.177.128 9000");
    7         return -1;
    8   }
    9   std::string ip=argv[1];
   10   uint16_t port=std::stoi(argv[2]);
   11   TcpSocket cli_sock;
   12   //创建套接字
   13   assert(cli_sock.Socket()!=false);
   14   //向服务端发起连接
   15  assert(cli_sock.Connect(ip,port));
   16  //循环收发数据
   17  while(1){
   18   std::string buf;
   19   std::cout<<"client say: ";
   20   fflush(stdout);
   21    std::cin>>buf;
   22    assert(cli_sock.Send(buf));
   23    buf.clear();
   24    assert(cli_sock.Recv(&buf));                                                                                                                                   
   25    std::cout<<"serve say: "<<buf<<std::endl;
   26  }
   27  //关闭套接字
   28  cli_sock.Close();
   29   return 0;
   30 }

    #include"tcp_socket.hpp"
    2 #include<signal.h>
    3    void create_worker(TcpSocket new_sock){
    4     pid_t pid=fork();
    5     if(pid<0){
    6       new_sock.Close();
    7       perror("fork error");
    8       return ;
    9     }
   10     if(pid>0){
   11       new_sock.Close();
   12       return;
   13     }
   14     while(1){
   15  //使用新建连接发送数据
   16        std::string buf; 
   17        bool ret=new_sock.Recv(&buf);
   18         if(ret==false){
   19          new_sock.Close();
   20           continue;
   21             }
   22           std::cout<<"client say"<<buf<<std::endl;
   23          buf.clear();
   24          std::cout<<"serve say";
   25          fflush(stdout);
   26          std::cin>>buf;
   27          new_sock.Send(buf);
   28        if(ret==false){
   29            new_sock.Close();                                                                                                                                      
   30             exit(-1); 
   31         }
   32     }
   33     exit(-1); 
   34   } 
   35      int main(int agc,char *argv[])
   36      {
   37        if(agc!=3){
   38          printf("usage: ./tcp_srv 192.168.177.128 9000");
   39          return -1;                                                                                                                                               
   40        }
   41        signal(SIGCHLD,SIG_IGN);
   42        std::string ip=argv[1];
   43        uint16_t port=std::stoi(argv[2]);                                                                                                                                      
      //服务器流程
   44       TcpSocket lsn_sock;
   45       //创建套接字
   46      assert( lsn_sock.Socket()!=false);
   47       //为套接字绑定地址信息
   48       assert(lsn_sock.Bind(ip,port));
   49       //开始监听
   50       assert(lsn_sock.Listen());
   51       //获取新建连接
   52       while(1){
   53        TcpSocket new_sock;
   54        std::string cli_ip;
   55        uint16_t cli_port;
   56        bool ret=lsn_sock.Accept(&new_sock,&cli_ip,&cli_port);
   57        if(ret==false){
   58          continue;
   59       }
   60        std::cout<<"new client:"<<cli_ip<<":"<<cli_ip<<std::endl;
   61        create_worker(new_sock);
   62       }
   63      //关闭套接字
   64       lsn_sock.Close();
   65      return 0;
   66     }

多线程方案实现:
相较于多进程版本,流程上没有大的差别,也是获取一个新建连接之后,创建一个线程程出来
注意事项:
1、线程间是共用同一个文件描述符表,因此对这个通信套接字描述符的操作,只能由负责这个描述符操作的线程进行关闭,其他的线程不能关闭。

2、局部变量的使用,线程创建的时候,千万要注意传参,不能因为传递局部变量地址, 而导致线程内访问的时候出现内存访问错误。 

    #include"tcp_socket.hpp"
    2 #include<pthread.h>
    3 void *thread_entry(void*arg){
    4   
    5       TcpSocket new_sock;
    6       long fd=(long)arg;
    7       new_sock.set(fd);
    8       while(1){
    9        std::string buf; 
   10       bool ret=new_sock.Recv(&buf);
   11         if(ret==false){
   12          new_sock.Close();
   13           break;
   14             }
   15           std::cout<<"client say"<<buf<<std::endl;
   16          buf.clear();
   17          std::cout<<"serve say";
   18          fflush(stdout);                                                                                                                                          
   19          std::cin>>buf;
   20          new_sock.Send(buf);
   21        if(ret==false){
   22            new_sock.Close();
   23            break;
   24         }
   25       }
   26       return NULL;
   27 }
   28 void create_worker(TcpSocket sock){
   29     pthread_t tid;
   30     int ret=pthread_create(&tid,NULL,thread_entry,(void *)sock.fd());
   31     if(ret!=0){
   32       perror("thread error");
   33       sock.Close();
   34       return ;
   35     }
   36     pthread_detach(tid);
   37 return ;
   38 
   39                                                                                                                                                                   
   40 }
   41    
   42      int main(int agc,char *argv[])
   43      {
   44        if(agc!=3){
   45          printf("usage: ./tcp_srv 192.168.177.128 9000");
   46          return -1;
   47        }
   48        std::string ip=argv[1];
   49        uint16_t port=std::stoi(argv[2]);                                                                                                                                     
   50     
   51       //服务器流程
   52       TcpSocket lsn_sock;
   53       //创建套接字
   54      assert( lsn_sock.Socket()!=false);
   55       //为套接字绑定地址信息
   56       assert(lsn_sock.Bind(ip,port));
   57       //开始监听
   58       assert(lsn_sock.Listen());
   59       //获取新建连接
   60       while(1){
   61        TcpSocket new_sock;
   62        std::string cli_ip;
   63        uint16_t cli_port;
   64        bool ret=lsn_sock.Accept(&new_sock,&cli_ip,&cli_port);
   65        if(ret==false){
   66          continue;
   67       }
   68        std::cout<<"new client:"<<cli_ip<<":"<<cli_ip<<std::endl;
   69        create_worker(new_sock);                                                                                                                                   
   70       }
   71     //关闭套接字
   72       lsn_sock.Close();
   73      return 0;
   74     }

tcp通信程序编写与运行中遇到的一些特殊情况:
连接断开:tcp是面向连接的通信,一旦连接断开就无法通信
问题:如何在代码中知道连接断开了?连接断开后,在代码中的体现是什么?
当recv函数接收数据的时候,返回0,代表的不仅仅是没有接收到数据,更多是为了表示连接断开了。当send函数发送数据的时候,程序直接异常(SIGPIPE)退出,因此如果网络通信中,不想让程序因为连接断开而导致发送数据的时候程序异常通很出,就对SIGPIPE信号进行处理。

问题:有时候网络程序关闭后,无法立即启动,会bind绑定地址报错,绑定失败,地址已经被使用网络通信程序,如果程序是主动关闭的一方,程序会无法立即启动
因为一个程序主动关闭了连接,这个连接并不会立即被释放(对应的地址和端口依然被占用),而是要等待一段时间。这时候,要不然换个端口绑定,要不然就等一会
netstat-anptu查看没有连接对应的信息了,则就可以绑定了,netstat命令,非常重要,这是查看主机上所有网络连接状态的命令。因为一个网络通信程序运行起来后,如果没有达到预期的目标,首先就要看程序对应的网络连接是否是正常的

a 查看所有信息
n不要以服务名称,显示端口或地址,比如127.0.0.1会被 识别为localhost,22端口会被识别为ssh,...

p显示网络连接信息的时候,顺便显示连接对应的进程ID和名称

t过滤只显示tcp套接字信息

u过滤只显示udp套接字信息

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

网络编程套接字 的相关文章

  • ubuntu环境下启动rosrun rqt_tf_treerqt_tf_tree出现错误的问题

    ubuntu下安装anconda3后启动rqt tf tree会报错 xff0c 信息为 xff1a 原因是安装rospy使用的是python2 但是anconda会把系统的python设置成python3 做法是在不改变anconda安装
  • 上层应用开发是否真的没有底层开发有前途?

    首先明确什么是底层开发 xff0c 这个界限很难划分 xff0c 有人说搞音视频底层编解码就是底层了 xff0c 但是我们看来不是这样 xff0c 下面还有rom中音视频模块 xff0c 再下面还有driver xff0c 最后到物理硬件
  • python http的请求和响应

    span class token triple quoted string string 34 34 34 http请求 请求行和空行是必须要有的 xff0c 请求体和请求头可以没有 请求格式 xff1a 请求行 xff0c 请求头 xff
  • ROS学习篇第(六)篇:通信

    目录 串口通信 ros serial 包的使用ROS分布式多机通信 ssh的使用 xff11 目的2 关于SSR3 实现4 问题 串口通信 ros serial 包的使用 下载 span class token function sudo
  • 小觅双目立体避障模组新品发布,发力AGV物流领域

    2019年9月17日 xff0c 第二十一届中国国际工业博览会 xff0c 在上海国家会展中心正式拉开帷幕 以 立体视觉技术提供商 身份参展本届工博会的MYNTAI小觅智能在展会现场发布了旗下首款针对AGV量身定制的小觅双目立体避障模组 2
  • 小觅双目摄像头深度高精版发布,精度可达毫米级

    今天 xff0c 第二十一届中国国际工业博览会 xff0c 在上海国家会展中心正式拉开帷幕 以 立体视觉技术提供商 身份参展本届工博会的MYNTAI小觅智能 xff0c 携其小觅深度摄像头旗下深度系列新品小觅双目摄像头深度高精版惊喜亮相 自
  • AGV搬运机器人「眼睛」的未来:3D视觉导航方案

    搬运机器人是可以进行自动化搬运作业的工业机器人 xff0c 也就是人们常提到的AGV 自动引导车 中的一个主流大类 随着工厂自动化 计算机集成制造系统技术逐步发展 xff0c 以及柔性制造系统 自动化立体仓库的广泛应用 xff0c AGV搬
  • 小觅双目摄像头标准版视觉惯性 SLAM DEMO

    说到 vins xff0c 就很难不让人想起另一个通过视觉与 imu 融合的经典 OKVIS 它是由 Stefan Leutenegge 等人提出的基于双目 43 惯导的视觉里程计 xff0c 属于 VIO Visual Inertial
  • 小觅智能 | OKVIS 学习笔记

    上一期的视觉里程计 xff0c 让我们想到了 OKVIS xff0c 知乎上的讨论也比较少 xff0c 小觅智能来分享一下 OKVIS 基本介绍 它是由 Stefan Leutenegge 等人提出的基于双目 43 惯导的视觉里程计 xff
  • 小觅双目摄像头标准彩色版发布 为移动机器人视觉导航避障优化设计

    2019年1月15日 xff0c 小觅智能发布了其双目深度相机系列旗下全新产品小觅双目摄像头标准彩色版 xff08 简称标准彩色版 xff0c 下同 xff09 小觅双目摄像头 标准彩色版 xff08 MYNT EYE S Color xf
  • Vins-Fusion 学习笔记

    VINS Fusion 基本介绍 VINS Fusion 是继 VINS Mono 和 VINS Mobile xff08 单目视觉惯导 SLAM 方案 xff09 后 xff0c 香港科技大学沈劭劼老师开源的双目视觉惯导 SLAM 方案
  • 我是如何通过阿里面试的?

    笔者参加18年阿里春招 xff0c 有幸最终拿到阿里offer xff0c base杭州 xff0c 岗位客户端开发 一直忙于其他事情 xff0c 拿到意向已经过去十多天 xff0c 在此分享一些关于面试的干货 xff0c 攒一波RP xf
  • 运行msckf_vio

    MSCKF vio是一种基于多状态约束卡尔曼滤波器的双目视觉里程计 其中多状态约束是指将多帧图像的相机位姿加入卡尔曼状态向量中 xff0c 在进行卡尔曼增益之前通过多帧图像之间的约束进行最小二乘优化来估计特征点的空间位置 xff0c 然后根
  • 建图 | SVO 论文与代码分析分讲

    建图 xff08 深度滤波器 xff09 VO 把像素的深度误差模型看做概率分布 xff0c 使用 高斯 均匀混合分布的逆深度 xff08 深度值服从高斯分布 xff0c 局外点的概率服从 Beta 分布 xff09 xff0c 称为 深度
  • 机房黑科技:京东数科机房巡检机器人

    6月11日 xff0c 第五届CES Asia亚洲消费电子展在上海正式开幕 京东数字科技携旗下多款机器人产品参展 xff0c 并正式发布了多款全新的智能机器人 其中 xff0c 室内运送机器人可以自主乘坐电梯 xff0c 并能自动导航 避障
  • AI深度 | 3D人脸识别和双目结构光惯导

    文 纽豪斯 发布 AI智道 一文看尽双目摄像 结构光 ToF和激光雷达技术 xff1b 一文深入了解小觅智能 奥比中光 华捷艾米 的卢深视 Pico和镭神智能 xff1b AI赋能2大趋势 4大核心技术 前言 纽豪斯刚刚完成 AI深度 xf
  • 经典笔试题——单向链表的倒序

    题目 xff1a 有一个单向链表 xff0c 将链表倒序 解决方案 xff1a 单向链表的特点 xff1a 链表节点只能从前往后遍历 xff08 不能从后往前遍历 xff09 xff0c 那么在遍历链表时 xff0c 必须从前往后处理这些数
  • 【CAN】手把手教你学习CAN总线(一)

    CAN总线 一 CAN总线概念二 CAN的差分信号三 CAN总线的通信协议1 帧起始2 仲裁段3 控制段4 数据段5 CRC段6 ACK段7 帧结束 四 CAN的位时序1 同步段 xff08 SS xff09 2 传播时间段 xff08 P
  • 【FreeRTOS(一)】FreeRTOS新手入门——初识FreeRTOS

    初识FreeRTOS 一 实时操作系统概述1 概念2 RTOS的必要性3 RTOS与裸机的区别4 FreeRTOS的特点二 FreeRTOS的架构三 FreeRTOS的代码架构 一 实时操作系统概述 1 概念 RTOS xff1a 根据各个
  • 使用结构体方式访问寄存器的原理

    朱老师单片机课程学习记录 3 6 5 使用结构体方式访问寄存器的原理 1 C语言访问寄存器的本质是C语言访问内存 xff0c 本质思路是 xff1a 定义一个指针 xff08 临时变量 xff09 指向这块内存 xff0c 然后 p 61

随机推荐