我们前面已经学习网络程序的一个很大的部分,由这个部分的知识,我们实际上可以写出大部分的基于TCP协议的网络程序了.
现在在 Linux下的大部分程序都是用我们上面所学的知识来写的.我们可以去找一些源程序来参考一下.这一章,我们简单的学习一下基于UDP协议的网络程序.
5.1 两个常用的函数
int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr * from int *fromlen)
int sendto(int sockfd,const void *msg,int len,unsigned int flags,struct sockaddr *to int tolen)
sockfd,buf,len的意义和read,write一样,分别表示套接字描述符,发送或接收的缓冲区及大小.
recvfrom负责从 sockfd接收数据,如果from不是NULL,那么在from里面存储了信息来源的情况,如果对信息的来源不感兴趣,可以将from和fromlen 设置为NULL.
sendto负责向to发送信息.此时在to里面存储了收信息方的详细资料.
5.2 一个实例
运行UDP Server程序
执行./server &
点击(此处)折叠或打开
- /* 服务端程序 server.c */
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <string.h>
- #include <unistd.h>
- #include <netdb.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <sys/types.h>
- #include <arpa/inet.h>
- #define SERVER_PORT 8000
- #define MAX_MSG_SIZE 1024
- void udps_respon(int sockfd)
- {
- struct sockaddr_in addr;
- int n;
- socklen_t addrlen;
- char msg[MAX_MSG_SIZE];
- while (1) { /* 从网络上读 和 写到网络上面去 */
- memset(msg, 0, sizeof(msg));
- addrlen = sizeof(struct sockaddr);
- /*
- *ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
- * struct sockaddr *src_addr, socklen_t * addrlen);
- */
- n = recvfrom(sockfd, msg, MAX_MSG_SIZE, 0,
- (struct sockaddr *) &addr, &addrlen);
- /* 显示服务端已经收到了信息 */
- fprintf(stdout, "I have received %s", msg);
- /*echo back*/
- /*
- *ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
- * const struct sockaddr *dest_addr, socklen_t addrlen);
- */
- sendto(sockfd, msg, n, 0, (struct sockaddr *) &addr, addrlen);
- }
- }
- int main(int argc, char *argv[])
- {
- int sockfd;
- struct sockaddr_in addr;
- #if 0
- struct sockaddr_in {
- sa_family_t sin_family;
- in_port_t sin_port;
- struct in_addr sin_addr;
- unsigned char sin_zero[8];
- };
- #endif
- if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- fprintf(stderr, "Socket Error:%s\n", strerror(errno));
- exit(1);
- }
- #ifdef _DEBUG_
- fprintf(stdout, "Create a new UDP socket, socket = %d\n", sockfd);
- #endif
- bzero(&addr, sizeof(struct sockaddr_in));
- addr.sin_family = AF_INET; /*ipv4 */
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- addr.sin_port = htons(SERVER_PORT);
- if (bind(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in))
- < 0) {
- fprintf(stderr, "Bind Error:%s\n", strerror(errno));
- exit(1);
- }
- #ifdef _DEBUG_
- fprintf(stdout, "Bound successfully.\n");
- #endif
- udps_respon(sockfd);
- close(sockfd);
- return 0;
- }
点击(此处)折叠或打开
- /* 客户端程序 */
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <string.h>
- #include <unistd.h>
- #include <netdb.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <sys/types.h>
- #include <arpa/inet.h>
- #define MAX_BUF_SIZE 1024
- void udpc_requ(int sockfd, const struct sockaddr_in *addr, socklen_t len)
- {
- char buffer[MAX_BUF_SIZE];
- int n;
- while (fgets(buffer, MAX_BUF_SIZE, stdin)) { /* 从键盘读入,写到服务端 */
- sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *) addr,
- len);
- bzero(buffer, MAX_BUF_SIZE);
- memset(buffer, 0, sizeof(buffer));
- /* 从网络上读,写到屏幕上 */
- n = recvfrom(sockfd, buffer, MAX_BUF_SIZE, 0, NULL, NULL);
- if (n <= 0) {
- fprintf(stderr, "Recv Error %s\n", strerror(errno));
- return;
- }
- buffer[n] = 0;
- fprintf(stderr, "get %s", buffer);
- }
- }
- int main(int argc, char *argv[])
- {
- int sockfd;
- unsigned short port;
- struct sockaddr_in addr;
- #if 0
- struct sockaddr_in {
- sa_family_t sin_family;
- in_port_t sin_port;
- struct in_addr sin_addr;
- unsigned char sin_zero[8];
- };
- #endif
- if (argc != 3) {
- fprintf(stderr, "Usage:%s \n", argv[0]);
- exit(1);
- }
- port = (unsigned short) strtol(argv[2], NULL, 10);
- if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0))
- < 0) {
- fprintf(stderr, "Create socket failed: %s\n", strerror(errno));
- exit(1);
- }
- #ifdef _DEBUG_
- fprintf(stdout, "Create a new UDP socket, socket = %d\n", sockfd);
- #endif
- /* 填充服务端的资料 */
- bzero(&addr, sizeof(struct sockaddr_in));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- /*int inet_pton(int af, const char *src, void *dst); */
- inet_pton(AF_INET, argv[1], &addr.sin_addr);
- /*
- *int connect(int sockfd, const struct sockaddr *addr,
- * socklen_t addrlen);
- */
- if (connect
- (sockfd, (struct sockaddr *) &addr,
- sizeof(struct sockaddr_in)) == -1) {
- fprintf(stderr, "connect error %s\n", strerror(errno));
- exit(1);
- }
- udpc_requ(sockfd, &addr, sizeof(struct sockaddr_in));
- close(sockfd);
- return 0;
- }
命令来启动服务程序。我们可以使用netstat -ntupl命令来观察服务程序绑定的IP地址和端口
可以看到udp处有“0.0.0.0:8000”的内容,说明服务程序已经正常运行,可以接收主机上任何IP地址且端口为8000的数据。
3、运行UDP Client程序
执行./client 127.0.0.1 8000
命令来启动客户程序,使用127.0.0.1来连接服务程序,执行效果如下:
Hello, World!
Hello, World!
this is a test
this is a test
^D
输入的数据都正确从服务程序返回了,按ctrl+d可以结束输入,退出程序。
阅读(1441) | 评论(0) | 转发(0) |