Socket---UDP编程

UDP编程


socket常见API
    //创建socket文件描述符(TCP/UDP,客户端 + 服务器)
    int socket(int domain,int type,int protocol)
    //绑定端口号(TCP/UDP,服务器)
    int bind(int socket , const struct sockaddr *address,
                                   socklen_t address_len)
    
    //开始监听socket (TCP,服务器)
    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);

这里我们通过完成一个回显式服务器来完成UDP传输的过程

sockaddr结构:
头文件:#include <sys/socket.h>
    struct sockaddr {  
         sa_family_t sin_family;//地址族
        char sa_data[14]; //14字节,包含套接字中的目标地址和端口信息               
       }; 
sockaddr_in结构:
 //头文件:
 #include<netinet/in.h>
 #include <arpa/inet.h>
 
struct  sockaddr_in {
short  int  sin_family;                      /* Address family */
unsigned  short  int  sin_port;       /* Port number */
struct  in_addr  sin_addr;              /* Internet address */
unsigned  char  sin_zero[8];         /* Same size as struct sockaddr */
};
struct  in_addr {
unsigned  long  s_addr;
};

typedef struct in_addr {
union {
            struct{
                        unsigned char s_b1,
                        s_b2,
                        s_b3,
                        s_b4;
                        } S_un_b;
           struct {
                        unsigned short s_w1,
                        s_w2;
                        } S_un_w;
            unsigned long S_addr;
          } S_un;
} IN_ADDR;

sin_family -> 指代协议族,在socket编程中只能是AF_INET
sin_port -> 存储端口号(使用网络字节顺序)
sin_addr -> 存储IP地址,使用in_addr这个数据结构
sin_zero -> 是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
s_addr -> 按照网络字节顺序存储IP地址

实例:
服务端:
//UDP版本
#include<sys/socket.h>
#include<sys/types.h>
#include<error.h>
#include<cstdio>
#include<cstring>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
int main()
{
  //1.创建一个socket
  //AF_INET 是 一个宏,表示使用ipv4协议
  //SOCK_DGRAM表示使用UDP协议
 //int socket(int domain, int type, int protocol);
  int sock = socket(AF_INET,SOCK_DGRAM,0);
    if(sock < 0) {  //创建失败
      perror("socket");
      return 1;
    }
  //2.给当前的socket绑定上一个ip + 端口号
  sockaddr_in addr;   //这是一个结构体
  addr.sin_family = AF_INET;
  //ip地址也是一个整数,也需要转成网络字节序,但是inet_addr帮我们转好了
  addr.sin_addr.s_addr  = inet_addr("0.0.0.0");   
  //这个是可以接收的IP地址,0代表所有的IP地址
 //主机字节序的数字转成网络字节序
  addr.sin_port = htons(9090);                   
  //9090端口无特殊含义,比较不常用
  int ret = bind(sock,(sockaddr*)&addr,sizeof(addr));
  if(ret < 0){
    perror("bind");
    return 1;
  }
  printf("sever start ok!\n");
  //3.处理服务器收到的请求
  while(1){
    //a)读取客户端的请求
    //面向数据报的函数接口
    sockaddr_in peer;
    socklen_t len = sizeof(peer);  //输入输出参数
    char buf[1024] = {0};   //缓冲区
    ssize_t n=recvfrom(sock,buf,sizeof(buf)-1,0,
        (sockaddr*)&peer,&len);
    if( n < 0)
    {
      perror("recvfrom");
      continue;
    }
    buf[n] = '\0';
    //b) 根据请求计算响应
    //此处响应和请求相同,只需要回复发来的信息即可
    //c) 把响应写回客户端
    n = sendto(sock,buf,strlen(buf),0,(sockaddr*)&peer,len);
    if(n < 0)
    {
      perror("sendto");
      continue;
    }
    printf("[%s:%d] buf: %s\n",inet_ntoa(peer.sin_addr),
        ntohs(peer.sin_port),buf);
  }
  close(sock);
  return 0;
}
客户端:
#include<cstdio>
#include<cstring>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
// .client 127.0.0.1
int main(int argc,char* argv[])
{
 //1.先创建一个socket
  int sock = socket(AF_INET,SOCK_DGRAM,0);
  if(sock < 0)
  {
    perror("socket");
    return 1;
  }
//客户端一般不需要bind
//bind意味着和某个具体的端口号连接在一起
//如果没有bind,操作系统会随机分配一个端口号
//如果是服务器程序不去bind,就会导致每次启动服务的端口都会变化
//客户端就没法连接了
//准备好服务器的sockaddr_in 结构
  sockaddr_in server_addr;
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = inet_addr(argv[1]);
  server_addr.sin_port = htons(9090);
//4.客户端直接发送数据即可
  while(1){
  char buf[1024] = {0};
  printf("请输入一段内容:");
  fflush(stdout);
  scanf("%s",buf);
  sendto(sock,buf,strlen(buf),0,
        (sockaddr*)&server_addr,sizeof(server_addr));
  //从服务器接收一下返回结果
  char buf_output[1024] = {0};
  //后两个参数填NULL表示不关注对端的地址
  recvfrom(sock,buf_output,sizeof(buf_output),0,NULL,NULL);
  printf("server resp: %s\n",buf_output);
  }
  return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值