基于数据报 (Datagram) 的编程:(UDP)

软件控制
程序的运行需要内存、 CPU 和一些系统资源。操作系统关心这类事情,但是一些程序还需要关心另一件事情:就是程序拥有者的允许。
从合法性的角度讲,需要有一个许可证来保证程序的合法运行,但是有些许可证却是带有限制的。
一种实施许可证技术是编写程序来执行许可证控制。通常的做法是设计从一个许可证服务器获得许可的应用程序。该服务器是一个进程,它授权应用程序的运行。
许可证服务器。程序不是从磁盘或密钥取得许可,而是从服务器进程取得。许可证服务器被一台计算机上多个用户共亭,服务器进程能够控制程序的使用人数、使用时间、使用地点甚至程序的使用方式。
许可证服务系统:
运行许可证程序的过程:
(1)用户 U 运行被许可的程序巳
(2) 程序 P 向服务器 S 请求运行许可;
(3) 服务器检查当前运行程序 P 的用户数;
(4) 如果上限未达到, S 给予许可,程序 P 运行;
(5) 如果达到上限, S 拒绝许可,程序 P 告诉 U 稍后再试。
UDP使用recvfrom 函数阻塞直到数据报到达。当数据报到达时,消息内容、返回地址和其长度将被复制到缓存中。

#include <stdlib.h>
int atoi(const char *nptr);
//函数将由nptr指向的字符串的起始部分转换为int。 
#include <unistd.h>
int gethostname(char *name, size_t len);
//gethostname()返回字符数组名称中的以NULL结尾的主机名,其长度为len个字节。 如果以null结尾的主机名太大而不适合,则该名称将被截断,并且不会返回错误
struct hostent *gethostbyname(const char *name);
//函数返回给定主机名称的hostent类型的结构。这里的名称是标准点表示法中的主机名或IPv4地址。如果名称是IPv4地址,则不执行查找,gethostbyname()仅将name复制到h_name字段中,并将其结构in_addr等同于返回的hostent结构的h_addr_list [0]字段。 如果名称不以点结尾,并且设置了环境变量HOSTALIASES,则HOSTALIASES指向的别名文件将首先被搜索名称. 除非名称以点结尾,否则搜索当前域及其父母。

服务器:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<errno.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include<arpa/inet.h>

#define oops(m,x) {perror(m);exit(x);}
#define HOSTLEN 256

    int get_internet_address(char * host,int len,int *portp,struct sockaddr_in *addrp)
{   
  strncpy(host,inet_ntoa(addrp->sin_addr),(size_t)len);
  *portp = ntohs(addrp->sin_port);
  return 0;
}

void say_who_called(struct sockaddr_in *addrp);

int main()
{
  int sock;
  struct sockaddr_in saddr;

  sock = socket(AF_INET,SOCK_DGRAM,0);
  if(sock == -1)
    return -1;

  saddr.sin_port = htons(4444);
  saddr.sin_family = AF_INET;
  saddr.sin_addr.s_addr = inet_addr("192.168.1.127");

  if(bind(sock,(struct sockaddr*)&saddr,sizeof(struct sockaddr))!=0)
    return -1;
  while(1)
  {
    int msglen = 0;
    struct sockaddr_in saddr1;
    char buf[1024] = {0};
    int len = sizeof(struct sockaddr);
    msglen = (int)recvfrom(sock,buf,1024,0,(struct sockaddr*)&saddr1,(socklen_t*)&len);
    if(msglen == -1)
    {
      perror("recvfrom");
      return -1;
    }
    buf[msglen] = '\0';
    printf("dgrecv:got a message:%s\n",buf);
    say_who_called(&saddr);
  }
  return 0;
}

void say_who_called(struct sockaddr_in *addrp)
{
  char host[BUFSIZ];
  int port;

  get_internet_address(host,BUFSIZ,&port,addrp);
  printf("from:%s:%d\n",host,port);
}

客户端:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

#define oops(m,x) {perror(m);exit(x);}

#define HOSTLEN 256
int make_internet_address(struct sockaddr_in *addrp);

int make_dgram_client_socket()
{
  return socket(PF_INET,SOCK_DGRAM,0);
}

int make_internet_address(struct sockaddr_in *addrp)
{

  memset((void *)addrp,0x00,sizeof(addrp));
  addrp->sin_port = htons(4444);
  addrp->sin_family = AF_INET;
  addrp->sin_addr.s_addr = inet_addr("192.168.1.127");
  return 0;
}

int get_internet_address(char * host,int len,int *portp,struct sockaddr_in *addrp)
{
  strncpy(host,inet_ntoa(addrp->sin_addr),(size_t)len);
  *portp = ntohs(addrp->sin_port);
  return 0;
}
int make_dgram_client_socket();
int make_internet_address(struct sockaddr_in*);

int main()
{
  int sock;
  char msg[BUFSIZ] ={0};
  struct sockaddr_in saddr;
  scanf("%s",msg);

  if((sock = make_dgram_client_socket()) == -1)
    oops("cannot make socket",2);
  make_internet_address(&saddr);
  if(sendto(sock,msg,strlen(msg),0,(struct sockaddr*)&saddr,sizeof(struct sockaddr)) == -1)
    oops("sento failed",3);
  return 0;
}

创建一个数据报 socket 与创建一个流 socket 类似。其不同点在于,这里设置 socket 的类型为 SOCK_DGRAM ,而且不要调用 listen 函数。

SOCK_STREAM 提供有序,可靠的双向连接字节流。 可以支持带外数据传输机制。

SOCK_DGRAM 支持数据报(固定最大长度的无连接,不可靠的消息)。

SOCK_SEQPACKET 为固定最大长度的数据报提供有序的,可靠的基于双向连接的数据传输路径; 消费者需要在每次输入系统调用时读取整个数据包。

SOCK_RAW 提供原始的网络协议访问。

SOCK_RDM 提供不保证排序的可靠数据报层。

SOCK_PACKET 已经过时,不应该在新的程序中使用;

SOCK_NONBLOCK 在新打开的文件描述中设置O_NONBLOCK文件状态标志。使用此标志可以节省对fcntl的额外调用,以实现相同的结果。

SOCK_CLOEXEC 在新文件描述符上设置close-on-exec(FD_CLOEXEC)标志。 请参阅open(2)中O_CLOEXEC标志的说明,这可能有用。
这里写图片描述

这里写图片描述

这里写图片描述

总结:
• 数据报是从一个 socket 发送到另一个 socket 的短消息。数据报 socket 是不连接的,
每个消息包含有目的地址。数据报 (UDP)socket 更加简单、快速,给系统增加的负荷
更小。
• 许可证服务器是用来对被许可程序实施许可证验证规则的。许可证服务器发布许
可,以短消息的形式发送给客户。
• 记录系统状态的服务器必须设计成可以处理服务器和客户端的崩溃事件。
• 有些许可证服务器为一个网络上的多个机器提供服务。有儿种设计方法,各有优
缺点。
• socket 可以有两种类型的地址:网络或本地。本地的 socket 地址叫做 Unix 域
socket 或名字 socketo 这种 socket 使用文件名作为地址,只能在一台机器上交互
数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值