原创:如何做linux下udp大文件传输
近日小弟做了个linux下用户数据报协议大文件传输程式发上来与大家共勉。
代码在 redhat 9.0 下编译通过。
最大测试无差错传输文件:288M
最大测试传输速度:6.5M/S
可能这里并不需要这种类型的帖子,但希望各位能代小弟转贴,因为网络上很难搜索到这种可以解决丢包问题的代码级实现方法,希望每一个需要的人都能看的到。
服务器端:
- #include<sys/socket.h>;
- #include<string.h>;
- #include<netinet/in.h>;
- #include<stdio.h>;
- #include<stdlib.h>;
- #include<fcntl.h>;
- #include<sys/stat.h>;
- #include<unistd.h>;
- #include<errno.h>;
- #include<sys/select.h>;
- #include<sys/time.h>;
- #include<unistd.h>;
- #include<sys/types.h>;
- #define SERV_PORT 2500
- #define MAX_SIZE 1024*40
- void recvUDP(char name[20],int sockfd)
- {
- int ret,fd;
- mode_t fdmode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
- char mesg[MAX_SIZE];
- fd_set rdset;
- struct timeval tv;
- int rlen,wlen;
- int i;
- fd = open(name,O_RDWR|O_CREAT|O_APPEND,fdmode);
- if(fd == -1)
- {
- printf("open file %s error:%n",name,strerror(errno));
- exit(-1);
- }
- for(i=0;;i++)
- {
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- FD_ZERO(&rdset);
- FD_SET(sockfd,&rdset);
- ret = select(sockfd+1,&rdset,NULL,NULL,&tv);
- if(ret == -1)
- {
- printf("select error %s\n",strerror(errno));
- exit(-1);
- }
- else if(ret==0)
- {
- printf("select timeout,continue circle\n");
- continue;
- }
- if(FD_ISSET(sockfd,&rdset))
- {
- memset(mesg,0,MAX_SIZE);
- rlen = read(sockfd,mesg,MAX_SIZE);
- if(rlen <=0 )
- {
- printf("read error %s\n",strerror(errno));
- exit(-1);
- }
- if(!strcmp(mesg,"end"))
- {
- printf("recv end.\n");
- break;
- }
- wlen = write(fd,mesg,rlen);
- if(wlen != rlen )
- {
- printf("write error %s\n",strerror(errno));
- exit(-1);
- }
- }
- printf("The %d times write\n",i);
- }
- close(fd);
- }
- int main(int argc, char *argv[])
- {
- int sockfd;
- int r;
- struct sockaddr_in servaddr;
- 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 = htonl(INADDR_ANY);
- servaddr.sin_port = htons(SERV_PORT);
- /*bind address and port to socket*/
- if(bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) == -1)
- {
- perror("bind error");
- exit(-1);
- }
- r = fcntl(sockfd, F_GETFL, 0);
- fcntl(sockfd, F_SETFL, r & ~O_NONBLOCK);
- recvUDP(argv[1],sockfd);
- 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<fcntl.h>;
- #include<sys/stat.h>;
- #include<errno.h>;
- #include<sys/sysinfo.h>;
- #include<sys/select.h>;
- #include<sys/time.h>;
- #include<unistd.h>;
- #define MAX_SIZE 1024*40
- #define SERV_PORT 2500
- void connectUDP(char name[20],int sockfd,struct sockaddr *pservaddr,socklen_t servlen)
- {
- char buf[MAX_SIZE];
- fd_set wrset;
- struct timeval tv;
- int rlen,wlen;
- int fd;
- int ret;
- int i;
- if(connect(sockfd,(struct sockaddr *)pservaddr,servlen) == -1)
- {
- perror("connet error");
- exit(1);
- }
- else
- printf("connect server ok!\n");
- fd = open(name,O_RDONLY);
- if(fd==-1)
- {
- printf("fopen error %s\n",strerror(errno));
- exit(-1);
- }
- i=0;
- while(1)
- {
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- FD_ZERO(&wrset);
- FD_SET(sockfd,&wrset);
- ret = select(sockfd+1,NULL,&wrset,NULL,&tv);
- if(ret == -1)
- {
- printf("select error %s\n",strerror(errno));
- exit(-1);
- }
- else if(ret==0)
- {
- printf("select timeout,continue circle\n");
- continue;
- }
- memset(buf,0,MAX_SIZE);
- if(FD_ISSET(sockfd,&wrset))
- {
- rlen = read(fd,buf,MAX_SIZE);
- if(rlen <0)
- {
- printf("fread data error %s\n",strerror(errno));
- exit(-1);
- }
- else if(rlen==0)
- {
- wlen = write(sockfd,"end",3);
- if(wlen !=3)
- {
- printf("write end error\n",strerror(errno));
- exit(-1);
- }
- printf("all complete\n");
- close(fd);
- close(sockfd);
- exit(0);
- }
- wlen = write(sockfd,buf,rlen);
- if(wlen != rlen)
- {
- printf("write data to sockfd error:%s\n",strerror(errno));
- exit(-1);
- }
- i++;
- usleep(500);
- printf("The %d times read\n",i);
- }
- }
- }
- int main(int argc ,char *argv[])
- {
- char *fh;
- struct sysinfo s_info;
- float time1,time2;
- int error1,error2;
- int sockfd;
- struct stat fsize;
- struct sockaddr_in servaddr;
- error1= sysinfo(&s_info);
- time1 = s_info.uptime;
- int r;
- if(argc != 3)
- {
- printf("useage:udpclient<IPaddress>;\n");
- exit(1);
- }
- 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);
- }
- fh = argv[2];
- sockfd =socket(AF_INET,SOCK_DGRAM,0);
- r = fcntl(sockfd, F_GETFL, 0);
- fcntl(sockfd, F_SETFL, r & ~O_NONBLOCK);
- connectUDP(argv[2],sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
- fprintf(stderr,"ServerIP:\t%s\n",argv[1]);
- if(stat(argv[2],&fsize) == -1)
- perror("failed to get fiel statusi\n");
- else
- fprintf(stderr,"file name:\t%s\nfile size:\t%dK\n",argv[2],fsize.st_size/1024);
- error2=sysinfo(&s_info);
- time2 = s_info.uptime;
- printf("tranfice file time =%fs\n",(time2-time1));
- }
复制代码
Makefile
- all:send recv
- send:send.c
- gcc -Wall send.c -o send
- recv:recv.c
- gcc -Wall recv.c -o recv
- clean:
- rm -rf send recv
复制代码
[ 本帖最后由 platinum 于 2006-5-12 12:02 编辑 ]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
希望大家可以转到任何可以转的linux论坛。谢谢!
大哥不会是让我们都当做范例学习吧.
赞一下LZ
请楼主以后发代码时,用 [ code ] 括起来,或者禁止显示表情,否则贴出的代码没法看
memset是多此一举,并且大大耗费时间。
很好啊,值得学习!
谢谢楼主。
为什么说这是 "可以解决丢包问题的代码级实现方法"??
哪里是亮点,lz讲明白点不好吗??
否则我读代码的时候会遗漏过去体会不到.
还有如果网络状况很差 或者 发送比接收的机器速度快 等情况下是否会能保证不丢报呢?
agree.
无知者无畏亚