udp广播组播

 udp广播服务端

#include "head.h"
//广播发送端
//udp 服务端
#define IP "192.168.125.255"
#define PORT 8888
int main(int argc, char const *argv[])
{
  int sfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (sfd == -1)
  {
    perror("socket error");
    return -1;
  }

//设置允许广播
int broadcast = 1;
 int bsk = setsockopt(sfd,SOL_SOCKET,SO_BROADCAST,&broadcast,sizeof(broadcast));
 if (bsk == -1)
 {
   perror("setsockopt error");
   return -1;
 }

  struct sockaddr_in sin;
  sin.sin_family = AF_INET;
  sin.sin_port = htons(PORT);
  sin.sin_addr.s_addr = inet_addr(IP);

  char buf[128] = "";
  while (1)
  {
    bzero(buf, sizeof(buf));
    //从键盘获取消息
    fgets(buf,sizeof(buf),stdin);
    buf[strlen(buf)-1] = 0;
    //发送消息
    sendto(sfd ,buf,sizeof(buf),0,(struct sockaddr *)&sin,sizeof(sin));
    printf("发送成功\n");
  }
  close(sfd);

  return 0;
}

udp广播客户端

#include "head.h"
//广播接收端
//255段是广播段
#define IP "192.168.125.255"
#define PORT 8888
int main(int argc, char const *argv[])
{
  int cfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (cfd == -1)
  {
    perror("socket error");
    return -1;
  }
  struct sockaddr_in cin;
  cin.sin_family = AF_INET;
  cin.sin_port = htons(PORT);
  cin.sin_addr.s_addr = inet_addr(IP);
  ///绑定广播地址
  if (bind(cfd, (struct sockaddr *)&cin, sizeof(cin)) == -1)
  {
    perror("bind error");
    return -1;
  }
  char buf[128] = "";
  while (1)
  {
    bzero(buf, sizeof(buf));
    read(cfd, buf, sizeof(buf));
    printf("收到广播消息为:%s\n", buf);
  }
  close(cfd);

  return 0;
}

上传下载

#include "head.h"
/*
tftp实现上传下载客户端
*/
//实现下载功能
int do_download(int cfd, struct sockaddr_in sin)
{
  //定义变量存储下载请求包
  char buf[516] = "";
  //定义变量存储文件名
  char fileName[40] = "";

  printf("请输入文件名:");
  scanf("%s", fileName);
  getchar();

  //组装请求包
  short *p1 = (short *)buf;
  *p1 = htons(1); //表明要下载

  char *p2 = buf + 2; //文件名段
  strcpy(p2, fileName);

  char *p4 = p2 + strlen(p2) + 1; //模式段
  strcpy(p4, "octet");

  int size = 4 + strlen(p2) + strlen(p4); //要发送数据的大小

  //向服务器发送下载请求
  if (sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) == -1)
  {
    perror("sendto error");
    return -1;
  }

  printf("请求成功\n");

  //循环接收回复服务器发来的消息
  //循环接收数据包
  int flag = 0;
  int fd = -1;
  int res;
  unsigned short num = 1;
  socklen_t addrlen = sizeof(sin);

  while (1)
  {
    bzero(buf, sizeof(buf));
    res = recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &addrlen);
    if (res < 0)
    {
      return -1;
    }
    if (3 == buf[1]) //数据包
    {
      if (0 == flag) //防止文件重复打开
      {
        //创建并打开filename文件
        fd = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, 0664);
        if (fd < 0)
        {
          return -1;
        }
        flag = 1;
      }
      //判断当前的块编号
      if (htons(num) == *(unsigned short *)(buf + 2))
      {
        //提取数据,写入到文件中
        if (write(fd, buf + 4, res - 4) < 0)
        {
          printf("fd:%d res=%d\n", fd, res);
          break;
        }
        //回复ACK包将数据包的操作码修改成4,发送数据包的前四个字节。
        buf[1] = 4;
        sendto(cfd, buf, 4, 0, (struct sockaddr *)&sin, sizeof(sin));

        //判断数据包的大小是否小于516
        if (res < 516)
        {
          printf("文件下载完成\n");
          break;
        }
        num++;
      }
      else if (5 == buf[1]) //错误包
      {
        //打印错误信息
        printf("ERROR:%s\n", buf + 4);
        break;
      }
    }
  }
  close(fd);
  return 0;
}

int do_upload(int sfd, struct sockaddr_in sin)
{
  char filename[20] = "";
  char buf[516] = "";

  bzero(buf, sizeof(buf));
START:
  printf("请输入要上传的文件名:");
  fgets(filename, sizeof(filename), stdin);
  filename[strlen(filename) - 1] = 0;
  if (access(filename, F_OK) != 0)
  {
    printf("文件不存在\n");
    goto START;
  }
  FILE *fp;
  fp = fopen(filename, "r");
  //发送下载请求包
  int size = sprintf(buf, "%c%c%s%c%s%c", 0, 2, filename, 0, "octet", 0);
  if (sendto(sfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
  {
    perror("sendto");
    return -1;
  }

  socklen_t addrlen = sizeof(sin);
  ssize_t res = 0;

  unsigned short num = 0; //记录数据包的编号

  //循环发送数据包,接收ACK
  while (1)
  {
    bzero(buf, sizeof(buf));
    res = recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &addrlen);
    if (res < 0)
    {
      perror("recvfrom");
      return -1;
    }
    if (4 == buf[1])
    {
      //构造数据包
      *((unsigned short *)buf) = htons(3);
      *((unsigned short *)(buf + 2)) = htons(num + 1);
      res = fread(buf + 4, 1, 512, fp);
      if (res != 512)
      {
        if (ferror(fp))
        {
          printf("读取错误\n");
          return -1;
        }

        else if (feof(fp))
        {
          printf("文件读取完毕\n");
        }
      }
      //发送数据包
      if (res == sendto(sfd, buf, res + 4, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
      {
        perror("sendto");
        fclose(fp);
        return -1;
      }
      if (res < 512)
      {
        printf("文件上传成功\n");
        break;
      }
      num++;
    }
    else
    {
      if (num == 0)
      {
        if (sendto(sfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        {
          perror("sendto");
          return -1;
        }
      }
      else
      {
        if (res == sendto(sfd, buf, res + 4, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        {
          perror("sendto");
          fclose(fp);
          return -1;
        }
      }
    }
  }
  fclose(fp);
  return 0;
}

int main(int argc, const char *argv[])
{
  if (argc != 2)
  {
    printf("input error\n");
    printf("usage:./a.out ip\n");
    return -1;
  }

  //1、创建套接字
  int cfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (cfd == -1)
  {
    perror("socket error");
    return -1;
  }

  //2、填充服务器地址信息结构体
  struct sockaddr_in sin;
  sin.sin_family = AF_INET;
  sin.sin_port = htons(69);
  sin.sin_addr.s_addr = inet_addr(argv[1]);

  int mune = -1;
  while (1)
  {
    system("clear"); //清屏
    printf("\t\t======1、下载=======\n");
    printf("\t\t======2、上传=======\n");
    printf("\t\t======0、退出=======\n");

    printf("请输入功能:");
    scanf("%d", &mune);
    getchar();

    //多分支选择
    switch (mune)
    {
    case 1:
    {
      do_download(cfd, sin);
    }
    break;

    case 2:
    {
      do_upload(cfd,sin);
    }
    break;
    case 0:
      goto POS;
    default:
      printf("输入功能有误,请重新输入\n");
    }

    //阻塞
    printf("输入任意键,按回车清空:");
    while (getchar() != '\n')
      ;
  }

POS:
  //关闭套接字
  close(cfd);

  return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值