linux下udp 网络间通信程序+书上没有提过的问题自己想法
2012-05-07 19:28
597 查看
经过五一好几天的娱乐,这几天翻过头又把socket的UDP编程反刍一下,借了几本书又思考了一下,又把给我解答问题的朋友们的留言看了一遍,对UDP的socket编程终于有所小获,在网络中跨平台试了一下,好使,甚是开心,并打算在此总结一下以供初入门的朋友们少走弯路,并在此感谢积极给我解答问题的朋友们 @圣何塞白话人 @mallon @zino @xinzaibing @mallon @dd 是你们让我懂得了开源的精神,我也会以开源支持者的身份积极参与其中。下面是我的正文。
Linux下的socket编程主要就是几个结构体和几个函数就可以实现用协议通信的功能。主要的结构体如下:
第二个结构体和第三个结构体其实内容是一样的,只是后面讲的要用到的socket的函数bind, recvfrom, sendto, listen, accept, recv, send 等函数中用到的参数都是struct sockaddr,但是赋值的时候还是用sockaddr_in方便,于是就略显“多此一举”的给struct sockaddr_in定义的结构体的成员变量赋值,在调用函数的时候再用(struct sockaddr*)强制转换一下(这些在书上都是不说的)。
主要需要调用的函数上面提到了一些,这里就不说了,用终端中的man可以查到很详细的东西。下面贴一下程序:
服务器程序:
客户端程序:
在实际情况下,服务器用的是公网IP地址,而我在学校用的校园网正好也是给每个学生分配公网IP地址(封杀路由器),所以正好就把本机的公网IP作为服务器的IP地址,端口随意设了一个没有用的。客户端的程序和书上不同之处(优点)在于:当客户端连接到主机之后(connect调用之后),检测一下是否读到服务器回复的消息,如果没有回复就显示错误并退出,防止接收不到消息一直等待。
在本机中测试良好;在网络环境中,我在本机中开启服务器端程序,同学在win下用udp小工具作为客户端,同样可以达到互联的功能。同学用的是CMCC,是私有IP地址。(但这都不是问题的关键,因为NAT的作用把私有IP地址和端口号都转变为公有的IP地址和另一个端口号)
在这篇文章中要重点说书上没有的东西:(按我的个人理解,由于还在不断学习中,共同进步为原则,写出来在批判的过程中一起发现本质)
1,socket到底是什么?
sockfd是int类型,但其实它是具有指针功能的(虽然它不是指针),但是在创建socket的同时已经开辟了一段存储空间,用于存放和此socket绑定的相关信息。虽然在表面上不是指针,但是通过socket号可以确定是哪段存储空间这样便确定是哪段信息,和指针功能一样。
2,在服务器程序中,在37行
对servaddr和cliaddr做了定义,但是后面只对servaddr赋值,cliaddr中只是定义时系统赋的初始值,用gdb显示如下:
但是,服务器得到了客户端发送的信息并且回复了客户端。它究竟是如何得到客户端的IP地址和端口号的呢?由于UDP是在传输层,很多下层一些的东西都不知道,要想弄明白这个我还需要继续学习(这也是我要做的),但是现在入门姑且这样理解,在这个日子mark一下,等发下一篇文章的时候就知道更本质的东西了,也知道我这些天到底有没有用功啦~~
姑且就这两个问题是书上没有解释的,现在的书都是一大抄,借来一堆书发现内容都一样,甚至程序都一样;还有的书程序很乱,编译都出错,书名就不提了,《21天。。。》。。。好了,期待自己的下一篇文章,也是下一个阶段(虽然我现在还很菜~~)。
Linux下的socket编程主要就是几个结构体和几个函数就可以实现用协议通信的功能。主要的结构体如下:
struct in_addr { in_addr_t s_addr; //in_addr_t 其实就是unsigned long }; struct sockaddr { unsigned short sa_family; char sa_data[14]; }; struct sockaddr_in { short int sin_family; unsigned short int sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; };
第二个结构体和第三个结构体其实内容是一样的,只是后面讲的要用到的socket的函数bind, recvfrom, sendto, listen, accept, recv, send 等函数中用到的参数都是struct sockaddr,但是赋值的时候还是用sockaddr_in方便,于是就略显“多此一举”的给struct sockaddr_in定义的结构体的成员变量赋值,在调用函数的时候再用(struct sockaddr*)强制转换一下(这些在书上都是不说的)。
主要需要调用的函数上面提到了一些,这里就不说了,用终端中的man可以查到很详细的东西。下面贴一下程序:
服务器程序:
#include <sys/types.h> #include <sys/socket.h> #include <string.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #define MAXLINE 80 #define sport 4567 #define sip "49.140.191.30" void do_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen) { int n; socklen_t len; char mesg[MAXLINE]; int i=0; while(1) { printf("OK %d\n",i); i++; len = clilen; /* waiting for receive data */ n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len); /* sent data back to client */ sendto(sockfd, mesg, n, 0, pcliaddr, len); } } /*主函数*/ int main(void) { int sockfd; struct sockaddr_in servaddr, cliaddr; sockfd = socket(AF_INET, SOCK_DGRAM, 0); /* create a socket */ /* init servaddr */ bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr=inet_addr(sip); //servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(sport); /* bind address and port to socket */ if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) { perror("bind error"); exit(1); } do_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)); return 0; }
客户端程序:
#include <sys/types.h> #include <sys/socket.h> #include <string.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <arpa/inet.h> #include <unistd.h> #define MAXLINE 80 #define SERV_PORT 4567 void do_cli(FILE *fp, int sockfd, struct sockaddr *pservaddr, socklen_t servlen) { int n; char sendline[MAXLINE], recvline[MAXLINE + 1]; /* connect to server */ if(connect(sockfd, (struct sockaddr *)pservaddr, servlen) == -1) { perror("connect error"); exit(1); } while(fgets(sendline, MAXLINE, fp) != NULL) { /* read a line and send to server */ write(sockfd, sendline, strlen(sendline)); /* receive data from server */ n = read(sockfd, recvline, MAXLINE); if(n == -1) { perror("read error"); exit(1); } recvline = 0; /* terminate string */ fputs(recvline, stdout); } } int main(int argc, char **argv) { int sockfd; struct sockaddr_in servaddr; /* check args */ if(argc != 2) { printf("usage: udpclient <IPaddress>\n"); exit(1); } /* init servaddr */ bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) { printf("[%s] is not a valid IPaddress\n", argv[1]); exit(1); } sockfd = socket(AF_INET, SOCK_DGRAM, 0); do_cli(stdin, sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); return 0; }
在实际情况下,服务器用的是公网IP地址,而我在学校用的校园网正好也是给每个学生分配公网IP地址(封杀路由器),所以正好就把本机的公网IP作为服务器的IP地址,端口随意设了一个没有用的。客户端的程序和书上不同之处(优点)在于:当客户端连接到主机之后(connect调用之后),检测一下是否读到服务器回复的消息,如果没有回复就显示错误并退出,防止接收不到消息一直等待。
在本机中测试良好;在网络环境中,我在本机中开启服务器端程序,同学在win下用udp小工具作为客户端,同样可以达到互联的功能。同学用的是CMCC,是私有IP地址。(但这都不是问题的关键,因为NAT的作用把私有IP地址和端口号都转变为公有的IP地址和另一个端口号)
在这篇文章中要重点说书上没有的东西:(按我的个人理解,由于还在不断学习中,共同进步为原则,写出来在批判的过程中一起发现本质)
1,socket到底是什么?
int sockfd; sockfd = socket(AF_INET, SOCK_DGRAM, 0);
sockfd是int类型,但其实它是具有指针功能的(虽然它不是指针),但是在创建socket的同时已经开辟了一段存储空间,用于存放和此socket绑定的相关信息。虽然在表面上不是指针,但是通过socket号可以确定是哪段存储空间这样便确定是哪段信息,和指针功能一样。
2,在服务器程序中,在37行
struct sockaddr_in servaddr, cliaddr;
对servaddr和cliaddr做了定义,但是后面只对servaddr赋值,cliaddr中只是定义时系统赋的初始值,用gdb显示如下:
(gdb) print cliaddr $5 = {sin_family = 45860, sin_port = 42, sin_addr = {s_addr = 2797556}, sin_zero = "U<\026\000Y\207\004\b"}
但是,服务器得到了客户端发送的信息并且回复了客户端。它究竟是如何得到客户端的IP地址和端口号的呢?由于UDP是在传输层,很多下层一些的东西都不知道,要想弄明白这个我还需要继续学习(这也是我要做的),但是现在入门姑且这样理解,在这个日子mark一下,等发下一篇文章的时候就知道更本质的东西了,也知道我这些天到底有没有用功啦~~
姑且就这两个问题是书上没有解释的,现在的书都是一大抄,借来一堆书发现内容都一样,甚至程序都一样;还有的书程序很乱,编译都出错,书名就不提了,《21天。。。》。。。好了,期待自己的下一篇文章,也是下一个阶段(虽然我现在还很菜~~)。
相关文章推荐
- [Linux网络编程]UDP编程--UDP通信程序服务器端
- [Linux网络编程]UDP编程--UDP通信程序客户端
- VS2010编写UDP网络通信程序的问题(借用孙鑫老师《深入VC++》书中程序)
- Linux下C语言多线程,网络通信简单聊天程序
- 一起来玩linux udp通信程序
- 解决Linux-CentOS 7.0 VMware虚拟机没有网卡不识别问题和Vmware提示无法将网络更改为桥接模式
- linux网络编程--第一弹UDP基本通信
- linux网络编程之socket(十四):基于UDP协议的网络程序
- Linux网络通信(二)Socket编写TCP/UDP
- 使用C#实现基于TCP和UDP协议的网络通信程序的基本示例
- Linux—网络通信(UDP)
- 关于linux下的udp/tcp通信设置发送sendto/接收recvfrom信息超时的参数。解决通道堵塞问题。
- LINUX 网络通信问题
- linux网络编程之socket(十四):基于UDP协议的网络程序
- linux中使用UDP实现网络通信
- Linux中Wine QQ上线 转变成离线问题的解决(什么时候才能自己修改?)(qq2012出了 那个没有这个BUG)
- [Linux网络编程]TCP编程--TCP通信程序服务器端
- 用java编写简单UDP网络通信程序
- linux网络编程之socket(十四):基于UDP协议的网络程序
- linux网络程序碰到的一些问题手记