UDP套接口编程

常用的UDP实现的程序:DNS域名系统,NFS网络文件系统,SNMP简单网络管理协议

ssize_t recvfrom(int sockfd,void *buff,size_t nbytes,int flags,struct sockaddr * from,socklen_t *addrlen);
ssize_t sendto(int sockfd,void *buff,size_t nbytes,int flags,struct sockaddr * to,socklen_t addrlen);

sockfd:描述字

buff:缓冲区指针

nbytes 读写字节数

 UDP服务器端

int main(int argc,char ** argv){
int sockfd;
struct sockaddr_in servaddr,cliaddr;
sockfd = Socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(sockfd,(SA *)&servaddr,sizeof(servaddr));
dg_echo(sockfd,(SA *)&cliaddr,sizeof(cliaddr));
}

void dg_echo(int sockfd,SA *pcliaddr,socklen_t clilen){
int n;
socklen_t len;
char mesg[MAXLINE];
for(;;){
    len = clilen;
    n = Recvfrom(sockfd,mesg,MAXLINE,0,pcliaddr,&len); //读一个到达的数据包
    Sendto(sockfd,mesg,n,0,pcliaddr,len); //发送回给客户机
}
}

SOCK_DGRAM:UDP套接口

1 函数不能终止

2 服务器是迭代服务器,没有fork调用,单一服务器进程处理所有客户。

UDP客户机程序:

int main(int argc,char ** argv){
int sockfd;
struct sockaddr_t servaddr;
if(argc != 2)
    err_quit("usage:udpcli<IPaddress>");
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET,argv[1],&servaddr,sin_addr); //装填套接字
sockfd = Socket(AF_INET,SOCK_DGRAM,0);
dg_cli(stdin,sockfd,(SA *)&servaddr,sizeof(servaddr));
exit(0);
}
void dg_cli(FILE *fp,int sockfd,const SA *pservaddr,socklen_t servlen){
int n;
char sendline[MAXLINE],recvline[MAXLINE+1];
while(Fgets(sendline,MAXLINE,fp) != NULL){ //从标准输入读一行
    Sendto(sockfd,sendline,strlen(sendline),0,pservaddr,servlen); //使用sendto发送给服务器
    n = Recvfrom(sockfd,recvline,MAXLINE,0,NULL,NULL); //使用recvfrom接收服务器回射,NULL无视目标主机
    recvline[n] = 0;
    Fputs(recvline,stdout); //fputs输出回射行到标准输出
}
}

改进的dg_cli

void dg_cli(FILE *fp,int sockfd,const SA * pservaddr,socklen_t servlen){
int n;
char sendline[MAXLINE],recvline[MAXLINE+1];
socklen_t len;
struct sockaddr *preply_addr;
preply_addr = Malloc(servlen);
while(Fgets(sendline,MAXLINE,fp)!= NULL ){
    Sendto(sockfd,sendline,strlen(sendline),0,pservaddr,servlen);
    len = servlen;
    n = Recvfrom(sockfd,recvline,MAXLINE,0,preply_addr,&len);
    if(len != servlen || memcpy(pservaddr,preply_addr,len) != 0){
        printf("reply from %s (ignored)\n");
                    Sock_ntop(preply_addr,len);
        continue;
    }
    recvline[n] = 0;
    Fputs(recvline,stdout);
}
}

解决办法:

1 给定由recvfrom返回的IP,在DNS中查找服务器验证

2 服务器配置每个IP地址创建套接口,捆绑IP地址此套接口,

仅在进程已将UDP套接口连接到确切的对方后,这些一步错误才返回给进程。

已连接的UDP套接口上调用connect达到下面两个目的:

1 指定IP地址和端口号

2 断开套接口

使用connect连接后再调用read write

void dg_cli(FILE *fp,int sockfd,const SA * pservaddr,socklen_t servlen){
    int n;
    char sendline[MAXLINE],recvline[MAXLINE+1];
    Connect(sockfd,(SA *)pservaddr,servlen);
    while(Fgets(sendline,MAXLINE,fp)!= NULL){
        Write(sockfd,sendline,strlen(sendline));
        n=Read(sockfd,recvline,MAXLINE);
        recvline[n] = 0;
        Fputs(recvline,stdout);
    }
}

对发送的UDP进行统计:

static void recvfrom_int(int);
static int count;
void dg_echo(int sockfd,SA *pcliaddr,socklen_t clilen){
    socklen_t len;
    char mesg[MAXLINE];
    Signal(SIGINT,recvfrom_int);
    for(;;){
        len = clilen;
        Recvfrom(sockfd,mesg,MAXLINE,0,pcliaddr,&len);

        count++;
    }
}
static void recvfrom_int(int signo){
    printf("\nreceived %d datagrams\n",count);
    exit(0);
}

UDP与TCP的服务器复用:

int main(int argc,char ** argv){
int listenfd,connfd,updfd,nready,maxfdp1;
char mesg[MAXLINE];
pid_t childpid;
fd_set rset;
ssize_t n;
socklen_t len;
const int on = 1;
struct sockaddr_in cliaddr,servaddr;
void sig_child(int);

listenfd = Socket(AF_INET,SOCKSTREAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_add=htonl(INADDR_ANY);
servaddr.sin_port=htons(SERV_PORT);
Setsockopt(listenfd,SOL_SOCKET,SO_RESSEADDR,&on,sizeof(on));
Bind(listenfd,(SA *)&servaddr,sizeof(servaddr));
Listen(listenfd,LISTENQ);

updfd=Socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(SERV_PORT);
Bind(udpfd,(SA *)&servaddr,sizeof(servaddr));

Signal(SIGCHLD,sig_chld);
FD_ZERO(&rset);
maxfdp1=max(listenfd,udpfd)+1;
for(;;){
    FD_SET(listenfd,&rset);
    FD_SET(udpfd,&rset);
    if((nready=select(maxfdp1,&rset,NULL,NULL,NULL,NULL))<0){
        if(errno==EINTR)
            continue;
        else
            err_sys("select error");
    }
    if(FD_ISSET(listenfd,&rset)){
        len = sizeof(cliaddr);
        connfd=Accept(listenfd,(SA *)&cliaddr,&len);
        if((childpid=Fork())==0){
            Close(listenfd);
            str_echo(connfd);
            exit(0);
        }
        Close(connfd);
    }
    if(FD_ISSET(udpfd,&rset)){
        len=sizeof(cliaddr);
        n=Recvfrom(udpfd,mesg,MAXLINE,0,(SA *)&cliaddr,&len);
        Sendto(udpfd,mesg,n,0,(SA *)&cliaddr,len);
    }
}
}

 

本文转自博客园xingoo的博客,原文链接:UDP套接口编程,如需转载请自行联系原博主。

时间: 2024-09-28 02:08:59

UDP套接口编程的相关文章

套接口编程

1 struct in_addr{ 2 in_addr_t s_addr; 3 }; 4 struct sockaddr_in{ 5 uint8_t sin_len; 6 sa_family_t sin_family; 7 in_port_t sin_port; 8 9 struct in_addr sin_addr; 10 char sin_zero[8]; 11 }; 通用套接口地址结构: struct sockaddr{ uint8_t sa_len; sa_family_t sa_fam

《UNIX网络编程 卷1:套接字联网API(第3版)》——第8章 基本UDP套接字编程 8.1概述

第8章 基本UDP套接字编程 8.1 概述 在使用TCP编写的应用程序和使用UDP编写的应用程序之间存在一些本质差异,其原因在于这两个传输层之间的差别:UDP是无连接不可靠的数据报协议,非常不同于TCP提供的面向连接的可靠字节流.然而相比TCP,有些场合确实更适合使用UDP,我们将在22.4节探讨这个设计选择.使用UDP编写的一些常见的应用程序有:DNS(域名系统).NFS(网络文件系统)和SNMP(简单网络管理协议). 图8-1给出了典型的UDP客户/服务器程序的函数调用.客户不与服务器建立连

Linux Socket学习--套接口的类型和协议

  我们首先来说一下PF_INET和AF_INET,虽然标准提倡在指定demain参数的时候,优先使用PF_INET,但是大量已经编写的c代码遵循旧的协议.目前情况是AF_UNIX=PF_UNIX,AF_INET=PF_INET.但是将来是不是这样不好说啊.           不同于socketpari函数的demain参数只能指定为PF_LOCAL,socket函数可以用于生成所支持的任何协议族的套接口,语法如下: #include <sys/types.h> #include <s

Linux中BSD套接口开发的基础介绍_unix linux

    这是关于如何用各种可以得到的接口为Linux开发网络程序的系列文章的第一篇.就像大多数Unix-based的操作系统一样,Linux支持将TCP/IP作为本地的网络传输协议.在这个系列中,我们假定你已经比较熟悉Linux上的C编程和Linux的一些系统知识诸如signals,forking等等. 这篇文章是关于如何用BSD套接口创建网络程序的基础介绍 .在下一篇中,我们会解决涉及到建立(网络)deamon进程的问题.而且今后的文章我们还会涉及到使用远程过程调用(RPC),以及用CORBA

C++UDP组播编程中,组播地址(组播号)与组播地址的关系是什么?和TCP中IP和端口的关系一样吗?

问题描述 C++UDP组播编程中,组播地址(组播号)与组播地址的关系是什么?和TCP中IP和端口的关系一样吗? C++UDP组播编程中,组播地址(组播号)与组播地址的关系是什么?和TCP中IP和端口的关系一样吗?另外,一台计算机上(不经过路由器或交换机)只能有一个组播吗?急求!!! 解决方案 组播地址和多播地支的关系与TCP中IP和端口的关系不太一样. 首先,网卡查看由信道传送过来的帧,确定是否接收该帧,若接收后就将它传往设备驱动程序.通常网卡仅接收那些目的地址为网卡物理地址或广播地址的帧. 使

简化spring(5)--减少不必要的基于接口编程

编程     众所周知,Spring是提倡基于接口编程的.    但也有些Service类,比如SaleOrderManager 和SaleOrderManagerImpl,只有5%的机会再有另一个Impl实现.95%时间里这两兄弟站一起,就像C++里的.h和.cpp,徒增维护的繁琐,所以刚开始用Spring的时候就想去掉它,今天偶然在群里聊起动态代理,算是搞明白了其中的道理,谢谢Sparkle :)      IOC是不会强制基于接口的,是这些Service类一般要使用Spring的声明式事务

从针对接口编程到依赖注入

1.概况说明 2.猫狗大战举例 3.说明为什么要针对接口编程,优点 4.说明为什么要"依赖抽象,不要依赖具体类" 5.说明"依赖倒置"与抽象工厂模式 6.说明"将组件的配置与使用分离" 7.简单说明依赖注入 8.讲解petshop依赖注入与它的工厂模式 9.讲解TheBeerHouse依赖注入形式 10.几个.Net的依赖注入容器 11.取舍与适用 概况说明 现在在各种技术站点.书籍文章上,都能看到IoC容器.控制反转.依赖注入的字眼,而且还会有

关于java与rs232接口编程的问题

问题描述 关于java与rs232接口编程的问题 最近公司给我个问题,就是用java编写rs232,邀请能读取和发送数据,有没有点高手,给点代码阿,包什么的都弄完了!谢谢各位大神.

针对接口编程

针对接口编程 针对接口编程: 针对接口编程,不要针对具体编程是依赖倒转原则的另外一种表述.针对接口编程又称为面向接口编程,针对接口编程就是要先设计一系列的接口,把设计和实现分离开. 其核心思想是,我们只提供你使用的接口,接口中的代码如何实现的我们不管,你可以更改接口中的内容,但接口的使用方法是永远也不会改变的. 以下用一个例子来说明,什么是针对接口编程. 加密解密是我们用的比较多的东西,有时候,公司开发的过程中用到了一种加密算法,输入字符串后经过加密算法处理了,然后输出加密过的字符串.可能一开始