LINUX C 基于TCP/IP协议的SOCKET收发文件的小例子。
自已没事正看这方面的东西,感觉要想把网络这块弄明白还真不是件简单的事。
程序写的比较繁琐,代码也不合理,有时间再把程序优化一下,加上断点继传的功能。。
/******** http://blog.csdn.net/robertkun ********/ /******* 服务器程序 (server.c) ************/ // linux 下读取大于2GB文件时,需指定 #define _FILE_OFFSET_BITS 64 #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> #include <fcntl.h> // 定义包的大小为512KB #define PACK_SIZE 1024*512 int main(int argc, char *argv[]) { // 设置输出缓冲 setvbuf(stdout, NULL, _IONBF, 0); fflush(stdout); int sockfd,new_fd; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int sin_size,portnumber; char hello[]="Hello! Are You Fine?\n"; if((portnumber=atoi("8080"))<0) { fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]); exit(1); } /* 服务器端开始建立socket描述符 */ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) { fprintf(stderr,"Socket error:%s\n\a",strerror(errno)); exit(1); } /* 服务器端填充 sockaddr结构 */ bzero(&server_addr,sizeof(struct sockaddr_in)); server_addr.sin_family=AF_INET; server_addr.sin_addr.s_addr=htonl(INADDR_ANY); server_addr.sin_port=htons(portnumber); /* 捆绑sockfd描述符 */ if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) { fprintf(stderr,"Bind error:%s\n\a",strerror(errno)); exit(1); } /* 监听sockfd描述符 */ if(listen(sockfd,5)==-1) { fprintf(stderr,"Listen error:%s\n\a",strerror(errno)); exit(1); } while(1) { fprintf(stderr, "server is listening!\n"); /* 服务器阻塞,直到客户程序建立连接 */ sin_size=sizeof(struct sockaddr_in); if( ( new_fd = accept(sockfd,(struct sockaddr *)(&client_addr),(socklen_t*)&sin_size ) ) == -1) { fprintf(stderr,"Accept error:%s\n\a",strerror(errno)); exit(1); } fprintf(stderr,"Server get connection from %s\n", inet_ntoa(client_addr.sin_addr)); if(write(new_fd,hello,strlen(hello))==-1) { fprintf(stderr,"Write Error:%s\n",strerror(errno)); exit(1); } long int read_size = 0; unsigned long file_len = 0; int order_id = 0; char file_name[128] = {'\0'}; char file_info[1024] = {'\0'}; // 读取指令 printf("\n\nWaiting for read file info!\n"); int nn = 0; if(nn = read(new_fd, file_info, 1024)) { // 指令ID int id_h = (int)file_info[0]<<8; order_id = id_h + (int)file_info[1]; // 文件长度 // 高16位 unsigned long len_hig_1 = 0; memcpy(&len_hig_1, &file_info[2], sizeof(file_info[2])); unsigned long len_hig_2 = 0; memcpy(&len_hig_2, &file_info[3], sizeof(file_info[3])); unsigned long len_hig = len_hig_1 * 256 + len_hig_2; // 低16位 unsigned long len_low_1 = 0; memcpy(&len_low_1, &file_info[4], sizeof(file_info[4])); unsigned long len_low_2 = 0; memcpy(&len_low_2, &file_info[5], sizeof(file_info[5])); int len_low = len_low_1 * 256 + len_low_2; file_len = len_hig * 256 * 256 + len_low; // 文件名称 strncpy(file_name, &file_info[6], strlen(&file_info[6])); printf("order = %d, %lu, %s\n", order_id, file_len, file_name); if((strlen(file_name) == 0) || (file_len == 0)) { printf("Read file info error!\n File_name or file_len is zero!\n"); close(new_fd); continue; } } else { printf("Read file info error!\n"); close(new_fd); close(sockfd); exit(0); } // 写入文件 printf("\n\nWaiting for read file content!\n"); FILE* pf = fopen(file_name, "wb+"); if(pf == NULL) { printf("Open file error!\n"); close(new_fd); continue; } char buff[PACK_SIZE] = {'\0'}; while(read_size <= file_len) { //bzero(buff, 1024); int rlen = read(new_fd, buff, PACK_SIZE); if(rlen) { //system("clear"); printf("\n\nRead package size = %d\n", rlen); int wn = fwrite(buff, sizeof(char), rlen, pf); read_size += rlen; printf("write file size = %d\n", wn); //printf("Read total size = %d\n", read_size); } else { printf("Read over!...%d\n", rlen); break; } } // End While printf("File len = %ld ... Already read size = %ld\n", file_len, read_size); /* 这个通讯已经结束 */ fclose(pf); close(new_fd); /* 循环下一个 */ } close(sockfd); exit(0); }
/******** http://blog.csdn.net/robertkun ********/ /******* 客户端程序 client.c ************/ // linux 下读取大于2GB文件时,需指定 #define _FILE_OFFSET_BITS 64 #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> #include <sys/stat.h> #include <fcntl.h> // 文件读写 // 定义包的大小为512KB #define PACK_SIZE 1024*512 char* get_file_name(char* fn); unsigned long get_file_size(const char *path); int main(int argc, char *argv[]) { if(argc < 2) { printf("please input:<ip> <port> <filePath>.\n"); return 0; } // 设置输出缓冲 setvbuf(stdout, NULL, _IONBF, 0); fflush(stdout); char* filePath = argv[3]; if(access(filePath, F_OK) != 0) { printf("file not existed!\n"); return 0; } int sockfd; char buff[1024] = {'\0'}; struct sockaddr_in server_addr; struct hostent *host; int portnumber,nbytes; const char* ip = argv[1]; if((host=gethostbyname(ip))==NULL) { fprintf(stderr,"Gethostname error\n"); exit(1); } const char* port = argv[2]; if((portnumber=atoi(port))<0) { fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[0]); exit(1); } /* 客户程序开始建立 sockfd描述符 */ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) { fprintf(stderr,"Socket Error:%s\a\n",strerror(errno)); exit(1); } /* 客户程序填充服务端的资料 */ bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family=AF_INET; server_addr.sin_port=htons(portnumber); server_addr.sin_addr=*((struct in_addr *)host->h_addr); /* 客户程序发起连接请求 */ if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) { fprintf(stderr,"Connect Error:%s\a\n",strerror(errno)); exit(1); } /* 连接成功了 */ if((nbytes=read(sockfd,buff,1024))==-1) { fprintf(stderr,"Read Error:%s\n",strerror(errno)); exit(1); } buff[nbytes]='\0'; printf("I have received:%s\n",buff); /******* 发送指令 ********/ bzero(buff,1024); // 指令ID int order = 0x0010; int order_h = order >> 8; buff[0] = (char)order_h; buff[1] = (char)order; // 文件长度 unsigned long len = get_file_size(filePath); printf("file size = %lu\n", len); // 高16位 int len_h = len >> 16; int len_h_1 = len_h >> 8; buff[2] = (char)len_h_1; buff[3] = (char)len_h; // 低16位 int len_l = len; int len_l_1 = len_l >> 8; buff[4] = (char)len_l_1; buff[5] = (char)len_l; // 文件名称 char* fileName = get_file_name(filePath); printf("file name = %s\n", fileName); strncpy(&buff[6], fileName, strlen(fileName)); write(sockfd,buff,1024); /******* 发送文件 ********/ printf("file path = %s\n", filePath); FILE* pf = fopen(filePath, "rb"); if(pf == NULL) { printf("open file failed!\n"); exit(0); } char pack[PACK_SIZE] = {'\0'}; while((len = fread(pack, sizeof(char), PACK_SIZE, pf)) > 0) { system("clear"); printf("send data size = %d \t", len); write(sockfd, pack, len); bzero(pack,PACK_SIZE); //sleep(1); } /* 结束通讯 */ close(sockfd); exit(0); } char* get_file_name(char* fn) { int last = 0; char* pfn = fn+strlen(fn)-1; int i=0; for(i=0; i<strlen(fn); ++i) { if(*pfn-- == '/') { last = strlen(fn)-i; break; } } char* name = (char*)malloc(sizeof(char)*256); char* pname = name; int j=0; for(j=last; j<strlen(fn); ++j, ++pname) { *pname = fn[j]; } return name; } unsigned long get_file_size(const char *path) { unsigned int filesize = 0; struct stat statbuff; if(stat(path, &statbuff) < 0) { printf("Get file stat failed!\n"); return filesize; }else{ filesize = statbuff.st_size; } return filesize; }
服务器端:
object=server.o server.o: gcc -g -c server.c gcc -o server $(object) clean: rm server $(object)
object=client.o client.o: gcc -g -c client.c gcc -o client $(object) clean: rm -rf client $(object)