UNP学习笔记(第八章 基本UDP套接字编程)
来源:互联网 发布:php查询数据库并输出 编辑:程序博客网 时间:2024/04/19 19:16
UDP应用程序客户不与服务器建立连接,而是只管使用sendto函数给服务器发送数据报,其中必须指定目的地的地址作为参数。View CodeView CodeView CodeView CodeView CodeView CodeView CodeView Code
下图给出典型的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函数
1 #include "unp.h" 2 3 int 4 main(int argc, char **argv) 5 { 6 int sockfd; 7 struct sockaddr_in servaddr, cliaddr; 8 9 sockfd = Socket(AF_INET, SOCK_DGRAM, 0);10 11 bzero(&servaddr, sizeof(servaddr));12 servaddr.sin_family = AF_INET;13 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);14 servaddr.sin_port = htons(SERV_PORT);15 16 Bind(sockfd, (SA *) &servaddr, sizeof(servaddr));17 18 dg_echo(sockfd, (SA *) &cliaddr, sizeof(cliaddr));19 }
dg_echo函数
1 #include "unp.h" 2 3 void 4 dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen) 5 { 6 int n; 7 socklen_t len; 8 char mesg[MAXLINE]; 9 10 for ( ; ; ) {11 len = clilen;12 n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);13 14 Sendto(sockfd, mesg, n, 0, pcliaddr, len);15 }16 }
UDP回射客户程序
main函数
1 #include "unp.h" 2 3 int 4 main(int argc, char **argv) 5 { 6 int sockfd; 7 struct sockaddr_in servaddr; 8 9 if (argc != 2)10 err_quit("usage: udpcli <IPaddress>");11 12 bzero(&servaddr, sizeof(servaddr));13 servaddr.sin_family = AF_INET;14 servaddr.sin_port = htons(SERV_PORT);15 Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);16 17 sockfd = Socket(AF_INET, SOCK_DGRAM, 0);18 19 dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));20 21 exit(0);22 }
dg_cli函数
1 #include "unp.h" 2 3 void 4 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen) 5 { 6 int n; 7 char sendline[MAXLINE], recvline[MAXLINE + 1]; 8 9 while (Fgets(sendline, MAXLINE, fp) != NULL) {10 11 Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);12 13 n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);14 15 recvline[n] = 0; /* null terminate */16 Fputs(recvline, stdout);17 }18 }
验证接收到的相应
知道客户临时端口的任何进程都可往客户发送数据报,而且这些数据报会与正常的服务器应答混杂。
我们应该修改recvfrom调用以返回数据报的发送者的IP地址和端口号,保留来自数据报所发往服务器的应答,而忽略任何其他数据报。
下面是验证返回套接字地址的dg_cli函数版本
1 #include "unp.h" 2 3 void 4 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen) 5 { 6 int n; 7 char sendline[MAXLINE], recvline[MAXLINE + 1]; 8 socklen_t len; 9 struct sockaddr *preply_addr;10 11 preply_addr = Malloc(servlen);12 13 while (Fgets(sendline, MAXLINE, fp) != NULL) {14 15 Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);16 17 len = servlen;18 n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);19 if (len != servlen || memcmp(pservaddr, preply_addr, len) != 0) {20 printf("reply from %s (ignored)\n",21 Sock_ntop(preply_addr, len));22 continue;23 }24 25 recvline[n] = 0; /* null terminate */26 Fputs(recvline, stdout);27 }28 }
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的新函数
1 #include "unp.h" 2 3 void 4 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen) 5 { 6 int n; 7 char sendline[MAXLINE], recvline[MAXLINE + 1]; 8 9 Connect(sockfd, (SA *) pservaddr, servlen);10 11 while (Fgets(sendline, MAXLINE, fp) != NULL) {12 13 Write(sockfd, sendline, strlen(sendline));14 15 n = Read(sockfd, recvline, MAXLINE);16 17 recvline[n] = 0; /* null terminate */18 Fputs(recvline, stdout);19 }20 }
使用select的TCP和UDP回射服务器程序
1 /* include udpservselect01 */ 2 #include "unp.h" 3 4 int 5 main(int argc, char **argv) 6 { 7 int listenfd, connfd, udpfd, nready, maxfdp1; 8 char mesg[MAXLINE]; 9 pid_t childpid;10 fd_set rset;11 ssize_t n;12 socklen_t len;13 const int on = 1;14 struct sockaddr_in cliaddr, servaddr;15 void sig_chld(int);16 17 /* 4create listening TCP socket */18 listenfd = Socket(AF_INET, SOCK_STREAM, 0);19 20 bzero(&servaddr, sizeof(servaddr));21 servaddr.sin_family = AF_INET;22 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);23 servaddr.sin_port = htons(SERV_PORT);24 25 Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));26 Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));27 28 Listen(listenfd, LISTENQ);29 30 /* 4create UDP socket */31 udpfd = Socket(AF_INET, SOCK_DGRAM, 0);32 33 bzero(&servaddr, sizeof(servaddr));34 servaddr.sin_family = AF_INET;35 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);36 servaddr.sin_port = htons(SERV_PORT);37 38 Bind(udpfd, (SA *) &servaddr, sizeof(servaddr));39 /* end udpservselect01 */40 41 /* include udpservselect02 */42 Signal(SIGCHLD, sig_chld); /* must call waitpid() */43 44 FD_ZERO(&rset);45 maxfdp1 = max(listenfd, udpfd) + 1;46 for ( ; ; ) {47 FD_SET(listenfd, &rset);48 FD_SET(udpfd, &rset);49 if ( (nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {50 if (errno == EINTR)51 continue; /* back to for() */52 else53 err_sys("select error");54 }55 56 if (FD_ISSET(listenfd, &rset)) {57 len = sizeof(cliaddr);58 connfd = Accept(listenfd, (SA *) &cliaddr, &len);59 60 if ( (childpid = Fork()) == 0) { /* child process */61 Close(listenfd); /* close listening socket */62 str_echo(connfd); /* process the request */63 exit(0);64 }65 Close(connfd); /* parent closes connected socket */66 }67 68 if (FD_ISSET(udpfd, &rset)) {69 len = sizeof(cliaddr);70 n = Recvfrom(udpfd, mesg, MAXLINE, 0, (SA *) &cliaddr, &len);71 72 Sendto(udpfd, mesg, n, 0, (SA *) &cliaddr, len);73 }74 }75 }76 /* end udpservselect02 */
sig_chld信号处理函数
1 Signal(SIGCHLD,sig_chld); 2 3 4 #include "unp.h" 5 6 void 7 sig_chld(int signo) 8 { 9 pid_t pid;10 int stat;11 12 pid = wait(&stat);13 printf("child %d terminated\n", pid);14 return;15 }
0 0
- UNP学习笔记(第八章 基本UDP套接字编程)
- UNP卷一学习笔记:基本UDP套接字编程
- UNP卷1:第八章(基本UNP套接字编程)
- UNP函数笔记六: 基本UDP套接字编程
- UNP学习笔记(第四章 基本TCP套接字编程)
- UNP学习笔记(第三章:套接字编程简介)
- UNP学习:基本套接字编程
- UNP笔记(2)——基本套接字编程
- UNP总结 Chapter 8 基本UDP套接字编程
- UNIX网络编程笔记 第八章 基本UDP套接字编程
- apue和unp的学习之旅10——基本udp套接字编程
- UNP函数笔记二: 基本TCP套接字编程
- UNP函数笔记七: 基本SCTP套接字编程
- UNP学习笔记(第七章 套接字选项)
- UNP学习笔记(第七章 套接字选项)
- UNP学习笔记(第十八章 路由套接字)
- UNP卷一学习笔记:基本TCP套接字
- 《UNIX网络编程卷1》读书笔记--第八章基本UDP套接字编程
- 如期而至,OC第二天
- C#学习之For循环
- 【Qt OpenGL教程】25:变形和从文件中加载3D物体
- UNP学习笔记(第六章 I/O复用)
- UNP学习笔记(第七章 套接字选项)
- UNP学习笔记(第八章 基本UDP套接字编程)
- UNP学习笔记(第十一章 名字与地址转换)
- Linux服务器性能评估与优化、监控利器---dstat应用
- UNP学习笔记(第十三章 守护进程和inetd超级服务器)
- OC-@property和@synthesize理解
- UNP学习笔记(第十四章 高级I/O函数)
- UNP学习笔记(第十五章 UNIX域协议)
- UNP学习笔记(第十六章 非阻塞I/O)
- UNP学习笔记(第十七章 ioctl操作)