网络套接字编程

1.端口和网络字节序

端口
在主机中表示一个进程,uint16_t --> 0-65535(0-1023特定)
每条数据当中都包括 源端口+目的端口
一个端口只能被一个进程所占用
一个进程可以占用多个端口
网络当中数据的五元组:源IP+源端口+目的IP+目的端口+协议
网络字节序
字节序:CPU对内存当中的数据进行存取的顺序
大端字节序:低地址存高位
小端字节序:低地址存地位
主机字节序:当前计算的字节序
网络字节序:大端字节序
转换接口

uint32_t htonl(uint32_t hostlong):将主机字节序的4个字节的数据转化成网络字节序
uint16_t htons(uint16_t hostshort); 将主机字节序的2个字节的数据转化成网络字节序
uint32_t ntohl(uint32_t netlong); 将网络字节序的4个字节的数据转换成主机字节序
uint16_t ntohs(uint16_t netshort)将网络字节序的2个字节的数据转换成主机字节序

2.TCP和UDP

TCP特点:
传输层协议、有连接、可靠传输、面向字节流
UDP特点:
传输层协议、无连接、不可靠传输、面向数据报

3.UDP实现

3.1 UDP实现流程

在这里插入图片描述
创建套接字,就是在内核中创建了一个struct socket{…},在这个结构体中有两个缓冲区,一个是接收缓冲取,一个是发送缓冲区。操作系统内核的职责是将网卡收到的数据,进行端口辨认之后,拷贝到不同的socket的缓冲区,程序员调用的操作系统定义的接口的时候(sendto,recvfrom),和socket缓冲区进行交互。

3.2 UDP接口

1.创建套接字

int socket(int domain,int type,int protocol);

domain: 地址域信息,网络层
参数:
AF_INET: ipv4
AF_INET6: ipv6
type:套接字类型
参数:
SOCK_STREAM: 流式套接字,默认传输层的协议是tcp,不支持udp
SOCK_DGRAM: 数据报套接字,默认的传输层的协议是udp,不支持tcp
protocol:协议类型
参数
0:使用套接字的默认协议
TCP: IPPROTO_TCP:6
UDP: IPPROTO_UDP:17
返回值:套接字的操作句柄,套接字描述符
2. 绑定地址信息

int bind(int sockfd,const struct sockaddr* addr,socklen_t len)

sockfd: 套接字操作句柄
addr
sockaddr:
地址类型,2个字节。
地址信息,14个字节char sa_data[14]。
ipv4:
地址类型,2字节。
uint16_t port, 2个字节
uint32_t ip, 4个字节
填充信息,8个字节
len:地址信息的长度
返回值成功返回0,失败返回-1
3. 发送数据

ssize_t sendto(int sockfd,const void *buf,size_t len,int flags,const struct sockaddr* dest_addr,socklen_t addrlen)

sockfd:套接字操作句柄
buf:要发送什么样的数据
len:要发送数据的长度
flags:一般设置为0,阻塞发送
dest_addr:目标地址信息
addrlen:地址信息的长度
4.接收数据

ssize_t recvfrom(int sockfd,void* buf,size_t len,int flags,struct sockaddr* src_addr,socklen_t* addrlen)

sockfd:套接字的操作句柄
buf:需要将接收到的数据存放到那里去
len’:接收数据buf的最大长度
flags:0,阻塞接受
src_addr:发送端地址信息
addrlen:地址信息长度
4. 关闭套接字

close(int sockfd)
3.3 代码实现

封装udp库,

//udpsvr.hpp
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<iostream>
#include<string>

class UdpSvr
{
   
  public:
    UdpSvr()
    {
   
      Sock_ = -1;

    }

    ~UdpSvr()
    {
   }

    bool CreateSock()
    {
   
      Sock_ = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
      if(Sock_ < 0)
      {
   
        perror("socket");
        return false;
      }
      return true;
    }
    bool Bind(std::string& ip,uint16_t port)
    {
   
      struct sockaddr_in addr;
      addr.sin_family = AF_INET;
      addr.sin_port = htons(port);
      addr.sin_addr.s_addr = inet_addr(ip.c_str());
      int ret = bind(Sock_,(struct sockaddr*)&addr,sizeof(addr));
      if(ret < 0)
      {
   
        perror("bind");
        return false;
      }
      return true;
    }
    bool Send(std::string&buf,struct sockaddr_in* destaddr)
    {
   
      int SendSize = sendto(Sock_,buf.c_str(),buf.size(),0,(struct sockaddr*)destaddr,sizeof(struct sockaddr_in));
      if(SendSize < 0)
      {
   
        perror("sendto");
        return  false;
      }
      return true;
    }
    bool Recv(std::string& buf,struct sockaddr_in* srcaddr)
    {
   
      char tmp[1024] = {
   0};
      socklen_t socklen = sizeof(struct sockaddr_in);
      int RecvSize = recvfrom(Sock_,tmp,sizeof(tmp) - 1,0,(struct sockaddr*)srcaddr,&socklen);
      if(RecvSize < 0)
      {
   
        perror("Recv");
        return false;
      }
      buf.assign(tmp,RecvSize);
      return true;

    }
    void Close()
    {
   
      close(Sock_);
      Sock_ = -1;
    }
private:
    int Sock_;
};

服务端

//svr.cpp
#include"udpsvr.hpp"

int main(int argc,char* argv[])
{
   
  if(argc != 3)
  {
   
    printf("./svr [ip] [port]\n");
    return 0;
  }
  std::string ip = argv[1];
  uint16_t port = atoi(argv[2]);
  UdpSvr us;
  if(!us.CreateSock())
  {
   
    return 0;
  }
  if(!us.Bind(ip,port))
  {
   
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值