UDP应用程序客户不与服务器建立连接,而是只管使用sendto函数给服务器发送数据报,其中必须指定目的地的地址作为参数。

下图给出典型的UDP客户/服务器程序的函数调用。

recvfrom和sendto函数

这两个函数类似于标准的read和write函数,不过需要3个额外的参数

#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags,const struct sockaddr *to, socklen_t addrlen);
//均返回:若成功则为读或写的字节数,若出错则为-1

UDP回射服务器程序

main函数

 #include    "unp.h"

 int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr, cliaddr; sockfd = Socket(AF_INET, SOCK_DGRAM, ); 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));
}

dg_echo函数

 #include    "unp.h"

 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, , pcliaddr, &len); Sendto(sockfd, mesg, n, , pcliaddr, len);
}
}

UDP回射客户程序

main函数

 #include    "unp.h"

 int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr; if (argc != )
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[], &servaddr.sin_addr); sockfd = Socket(AF_INET, SOCK_DGRAM, ); dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr)); exit();
}

dg_cli函数

 #include    "unp.h"

 void
dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + ]; while (Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), , pservaddr, servlen); n = Recvfrom(sockfd, recvline, MAXLINE, , NULL, NULL); recvline[n] = ; /* null terminate */
Fputs(recvline, stdout);
}
}

验证接收到的相应

知道客户临时端口的任何进程都可往客户发送数据报,而且这些数据报会与正常的服务器应答混杂。

我们应该修改recvfrom调用以返回数据报的发送者的IP地址和端口号,保留来自数据报所发往服务器的应答,而忽略任何其他数据报。

下面是验证返回套接字地址的dg_cli函数版本

 #include    "unp.h"

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

UDP的connect函数

UDP套接字可以调用connect,但是跟TCP套接字不一样,它不会有三次握手过程。

对于已连接的套接字,与默认的未连接套接字相比,发生了三个变化:

1.我们再也不能给输出操作指定目的IP地址和端口号。也就是说,我们不使用sendto而改用write或send。

2.我们并不必使用recvfrom以获悉数据报的发送者,而改用read、recv或recvmsg。

3.由已连接UDP套接字引发的异步错误会返回给它们所在的进程,而未连接UDP套接字不接受任何异步错误。

一个已连接的UDP套接字可以再次调用connect以用于:

1.指定新的IP地址和端口号

2.断开套接字

dg_cli函数(修订版)

把上面dg_cli函数重写成调用connect的新函数

 #include    "unp.h"

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

使用select的TCP和UDP回射服务器程序

 /* include udpservselect01 */
#include "unp.h" int
main(int argc, char **argv)
{
int listenfd, connfd, udpfd, nready, maxfdp1;
char mesg[MAXLINE];
pid_t childpid;
fd_set rset;
ssize_t n;
socklen_t len;
const int on = ;
struct sockaddr_in cliaddr, servaddr;
void sig_chld(int); /* 4create listening TCP socket */
listenfd = Socket(AF_INET, SOCK_STREAM, ); bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT); Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); /* 4create UDP socket */
udpfd = Socket(AF_INET, SOCK_DGRAM, ); 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));
/* end udpservselect01 */ /* include udpservselect02 */
Signal(SIGCHLD, sig_chld); /* must call waitpid() */ FD_ZERO(&rset);
maxfdp1 = max(listenfd, udpfd) + ;
for ( ; ; ) {
FD_SET(listenfd, &rset);
FD_SET(udpfd, &rset);
if ( (nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < ) {
if (errno == EINTR)
continue; /* back to for() */
else
err_sys("select error");
} if (FD_ISSET(listenfd, &rset)) {
len = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &len); if ( (childpid = Fork()) == ) { /* child process */
Close(listenfd); /* close listening socket */
str_echo(connfd); /* process the request */
exit();
}
Close(connfd); /* parent closes connected socket */
} if (FD_ISSET(udpfd, &rset)) {
len = sizeof(cliaddr);
n = Recvfrom(udpfd, mesg, MAXLINE, , (SA *) &cliaddr, &len); Sendto(udpfd, mesg, n, , (SA *) &cliaddr, len);
}
}
}
/* end udpservselect02 */

sig_chld信号处理函数

 Signal(SIGCHLD,sig_chld);

 #include    "unp.h"

 void
sig_chld(int signo)
{
pid_t pid;
int stat; pid = wait(&stat);
printf("child %d terminated\n", pid);
return;
}

UNP学习笔记(第八章 基本UDP套接字编程)的更多相关文章

  1. UNP学习笔记(第七章 套接字选项)

    有多种方法获取和设置影响套接字的选项: 1.getsockopt和setsockopt函数 2.fcntl函数 3.ioctl函数 getsockopt和setsockopt函数 这两个函数仅用于套接 ...

  2. 《Unix 网络编程》08:基本UDP套接字编程

    基本UDP套接字编程 系列文章导航:<Unix 网络编程>笔记 UDP 概述 流程图 recvfrom 和 sendto #include <sys/socket.h> ssi ...

  3. 【Python网络编程】利用Python进行TCP、UDP套接字编程

    之前实现了Java版本的TCP和UDP套接字编程的例子,于是决定结合Python的学习做一个Python版本的套接字编程实验. 流程如下: 1.一台客户机从其标准输入(键盘)读入一行字符,并通过其套接 ...

  4. 探索UDP套接字编程

    UDP和TCP处于同一层网络模型中,也就是运输层,基于二者之上的应用有很多,常见的基于TCP的有HTTP.Telnet等,基于UDP有DNS.NFS.SNMP等.UDP是无连接,不可靠的数据协议服务, ...

  5. 【转】 探索UDP套接字编程

    UDP和TCP处于同一层网络模型中,也就是运输层,基于二者之上的应用有很多,常见的基于TCP的有HTTP.Telnet等,基于UDP有DNS.NFS.SNMP等.UDP是无连接,不可靠的数据协议服务, ...

  6. JavaTCP和UDP套接字编程

    在我们刚开始入门Java后端的时候可能你会觉得有点复杂,包含了很多杂七杂八的知识,例如文件上传下载,监听器,JDBC,请求重定向,请求转发等等(当然也没有很多),但是我们自己真正的去开发一个小型网站( ...

  7. 计算机网络实验 UDP套接字编程

    这是个傻瓜式操作教程 西科大计算机网络实验 UDP套接字编程 我用自己的Ubuntu16.04来举例,实验室的是虚拟机,差不多 只针对第三个题目,修改服务器来通过响应客户端发送的GetTime并发送给 ...

  8. UDP套接字编程 返回系统时间

    计算机网络实验 简单UDP套接字编程 这是学校老师自己改进了一点的题目.我预习了好久才搞明白,同学来问的时候,一大堆简单问题实在是不想回答...所以,这时候我觉得博客是个好东西! 我的任务是做客户端和 ...

  9. 【Unix网络编程】chapter8基本UDP套接字编程

    chapter8基本UDP套接字编程 8.1 概述 典型的UDP客户端/服务端的函数调用 8.2 recvfrom和sendto函数 #include <sys/socket.h> ssi ...

随机推荐

  1. eclipse删除svn下载的文件后如何恢复

    Team右键-->与资源库同步-->覆盖/更新

  2. top/free/df/jstack/jmap

    上面的输出,load average后面分别是1分钟.5分钟.15分钟的负载情况.数据是每隔5秒钟检查一次活跃的进程数,然后根据这个数值算出来的.如果这个数除以CPU 的数目,结果高于5的时候就表明系 ...

  3. BZOJ 1096: [ZJOI2007]仓库建设(DP+斜率优化)

    [ZJOI2007]仓库建设 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在 ...

  4. BZOJ1566 [NOI2009]管道取珠 【dp】

    题目 输入格式 第一行包含两个整数n, m,分别表示上下两个管道中球的数目. 第二行为一个AB字符串,长度为n,表示上管道中从左到右球的类型.其中A表示浅色球,B表示深色球. 第三行为一个AB字符串, ...

  5. HDU 3792 素数打表

    Description If we define dn as: dn = pn+1-pn, where pi is the i-th prime. It is easy to see that d1 ...

  6. mongodb学习(2)--- nodeJS与MongoDB的交互(使用mongodb/node-mongodb-native)

    转载:http://www.cnblogs.com/zhongweiv/p/node_mongodb.html 目录 简介 MongoDB安装(windows) MongoDB基本语法和操作入门(mo ...

  7. 洛谷 [P3496] BLO

    割点 首先 tarjan 求割点, 对于不是割点的点, 答案是 2 * (n-1) 有序,所以要乘 2 对于是割点的点, 答案是删去该点后所有连通块的个数加上 n-1 在乘 2 #include &l ...

  8. js动态添加select菜单 联动菜单

    原文发布时间为:2009-11-14 -- 来源于本人的百度文章 [由搬家工具导入] <html> <head> <title>http://hi.baidu.co ...

  9. css3 实现多行文本折行

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. java中Map的entrySet 和keySet的使用

    存储这样的一个数据关系结构  使用嵌套map存储 可以通过调用  entrySet方法  或者 keySet方法 进行迭代或者增强for循环 便利输出 这里演示 迭代器的方式进行遍历 package ...