标签:
1 //*****客户端****** 2 /*功能: (1) input>list 查看服务端目录内容 3 (2) input>get files 下载文件 4 (3) input>put file 上传文件*/ 5 6 #include <head.h> 7 8 #define UPLOAD_FILE 1 9 #define DOWNLOAD_FILE 2 10 #define FILE_YEXIST 3 11 #define FILE_NEXIST 4 12 #define LIST_DIR 5 13 #define LIST_OVER 6 14 15 //定义协议报头结构体 16 typedef struct 17 { 18 unsigned char type; 19 unsigned char file_name[256]; 20 unsigned char file_type; 21 unsigned int file_size; 22 }__attribute__ ((__packed__))head_t;//取消结构体内存自动对齐 23 24 //初始化客户端套接字 25 int init_tcp_client_socket(const char *server_ip,const char *server_port, 26 const char *client_ip,const char *client_port) 27 { 28 int ret; 29 int sockfd; 30 struct sockaddr_in server_addr; 31 struct sockaddr_in client_addr; 32 33 sockfd = socket(AF_INET,SOCK_STREAM,0); 34 if(sockfd < 0){ 35 perror("Fail to socket"); 36 exit(EXIT_FAILURE); 37 } 38 //该段代码实现固定客户端ip,port 39 if(client_ip != NULL && client_port != NULL){ 40 client_addr.sin_family = AF_INET; 41 client_addr.sin_port = htons(atoi(client_port)); 42 client_addr.sin_addr.s_addr = inet_addr(client_ip); 43 ret = bind(sockfd,(struct sockaddr *)&client_addr,sizeof(client_addr)); 44 if(ret < 0){ 45 perror("Fail to bind"); 46 exit(EXIT_FAILURE); 47 } 48 } 49 //填充服务端地址、端口信息 50 server_addr.sin_family = AF_INET; 51 server_addr.sin_port = htons(atoi(server_port)); 52 server_addr.sin_addr.s_addr = inet_addr(server_ip); 53 //connect server 54 ret = connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)); 55 if(ret < 0){ 56 perror("Fail to connect"); 57 exit(EXIT_FAILURE); 58 } 59 60 return sockfd; 61 } 62 63 //上传 64 int do_put(int sockfd,const char *filename) 65 { 66 int n; 67 int fd; 68 int ret; 69 int count = 0; 70 char buf[1024]; 71 unsigned long total_size; 72 head_t *head = (head_t *)buf;//报头存放于栈上,此处用到了强转 73 74 fd = open(filename,O_RDONLY); 75 if(fd < 0){ 76 fprintf(stderr,"Fail to open %s : %s\n",filename,strerror(errno)); 77 goto error_open; 78 } 79 80 total_size = lseek(fd,0,SEEK_END); 81 lseek(fd,0,SEEK_SET); 82 83 //填充协议头信息,发送协议 84 head->type = UPLOAD_FILE; 85 strcpy(head->file_name,filename); 86 head->file_type = ‘-‘; 87 head->file_size = total_size; 88 ret = send(sockfd,buf,sizeof(head_t),0); 89 if(ret < 0){ 90 perror("Faio to send"); 91 goto error_send; 92 } 93 94 //发送文件内容 95 while(n = read(fd,buf,sizeof(buf))) 96 { 97 ret = send(sockfd,buf,n,0); 98 if(ret < 0){ 99 perror("Faio to send"); 100 goto error_send; 101 } 102 103 count += n; 104 105 fprintf(stderr,"send %d bytes : %%%.2f\r",count, (float)count / total_size * 100); 106 usleep(500); 107 } 108 printf("\n"); 109 110 close(fd); 111 close(sockfd);//关闭写端,告知服务器没有数据可发送 112 113 return 0; 114 115 116 error_send: 117 close(fd); 118 error_open: 119 close(sockfd); 120 return -1; 121 } 122 123 //客户端下载文件:[1]请求服务器端要下载文件(发送协议) 124 // [2]等待服务端结果 125 // [3]如果文件存在,则创建文件,读套接字,写文件 126 int do_get(int sockfd,char *filename) 127 { 128 int n; 129 int ret; 130 int fd; 131 int count = 0; 132 char buf[1024]; 133 unsigned long total_size; 134 head_t *head = (head_t *)buf; 135 136 //填充协议内容,并发送 137 head->type = DOWNLOAD_FILE; 138 strcpy(head->file_name,filename); 139 head->file_type = ‘-‘; 140 head->file_size = 0; 141 142 ret = send(sockfd,buf,sizeof(head_t),0); 143 if(ret < sizeof(head_t)){ 144 perror("Fail to send"); 145 goto error_handler; 146 } 147 148 //等待服务端结果(接收服务端返送回来的协议头,判断请求文件是否存在) 149 while(1) 150 { 151 n = recv(sockfd,buf + count ,sizeof(head_t) -count,0);//接收完整协议头,防止粘包 152 if(n <= 0){ 153 goto err_recv; 154 } 155 156 count += n; 157 if(count >= sizeof(head_t)) 158 break; 159 } 160 //如果返送回来的信息不存在 161 if(head->type == FILE_NEXIST){ 162 printf("You want download file:%s not exist !\n",filename); 163 goto error_handler; 164 } 165 166 //如果文件存在,得到请求文件的大小 167 total_size = head->file_size; 168 //打开文件 169 fd = open(filename,O_WRONLY | O_CREAT | O_TRUNC,0666); 170 if(fd < 0){ 171 fprintf(stderr,"Fail to open %s : %s\n",filename,strerror(errno)); 172 goto error_handler; 173 } 174 175 count = 0; 176 //循环接收,并写入 177 while(1) 178 { 179 n = recv(sockfd,buf,sizeof(buf),0); 180 if(n <= 0){ 181 break; 182 } 183 184 ret = write(fd,buf,n); 185 if(ret < 0) 186 break; 187 188 count += n; 189 fprintf(stderr,"download %d bytes : %%%.2f\r",count, (float)count / total_size * 100); 190 usleep(500);//延时,stderr,让下载情况实时显现 191 192 if(count >= total_size)//如果接收总字节大于文件总大小,跳出 193 break; 194 } 195 //刚好相等,下载完成,否则失败 196 if(count == total_size){ 197 printf("download success!\n"); 198 }else{ 199 printf("download failed,download %d bytes!\n",count); 200 close(fd); 201 goto error_handler; 202 } 203 204 close(fd); 205 close(sockfd); 206 207 return 0; 208 209 error_handler: 210 close(sockfd); 211 err_recv: 212 return -1; 213 } 214 215 //列出服务端目录文件内容 216 int do_list(int sockfd) 217 { 218 int n; 219 int ret; 220 int fd; 221 int count = 0; 222 char buf[1024]; 223 unsigned long total_size; 224 head_t *head = (head_t *)buf; 225 226 //send head 227 head->type = LIST_DIR; 228 ret = send(sockfd,buf,sizeof(head_t),0); 229 if(ret < sizeof(head_t)){ 230 perror("Fail to send"); 231 return -1; 232 } 233 234 //wait sever result 235 while(1) 236 { 237 count = 0; 238 //接收完整协议头 239 while(1) 240 { 241 n = recv(sockfd,buf + count ,sizeof(head_t) - count,0); 242 if(n <= 0){ 243 goto err_recv; 244 } 245 count += n; 246 if(count >= sizeof(head_t)) 247 break; 248 } 249 //目录不存在 250 if(head->type == LIST_OVER){ 251 break; 252 } 253 printf("%s\n",head->file_name);//打印目录下的文件名 254 } 255 256 close(sockfd); 257 return 0; 258 259 err_recv: 260 close(sockfd); 261 return -1; 262 } 263 264 //执行函数 265 int do_task(int sockfd,char *string) 266 { 267 char *pcmd; 268 char *pname; 269 //分割字符串,第一次调用,传递要分割字符,对同一字符连续分割,第一个参数指定为NULL 270 pcmd = strtok(string," "); 271 pname = strtok(NULL," ");//得到分割后的第二个字符串 272 273 if(strcmp(pcmd,"list") == 0){ 274 do_list(sockfd); 275 }else if(strcmp(pcmd,"get") == 0){ 276 do_get(sockfd,pname); 277 }else if(strcmp(pcmd,"put") == 0){ 278 do_put(sockfd,pname); 279 }else if(strcmp(pcmd,"quit") == 0){ 280 return -1; 281 }else{ 282 printf("Unknow cmd : %s\n",pcmd); 283 } 284 285 return 0; 286 } 287 288 289 //./tcp_server server_ip server_port 290 int main(int argc, const char *argv[]) 291 { 292 int ret = 0; 293 int sockfd; 294 char buf[256]; 295 296 if(argc < 3){ 297 fprintf(stderr,"Usage : %s <server_ip> <server_port>\n",argv[0]); 298 return -1; 299 } 300 301 while(1) 302 { 303 printf("input>"); 304 fgets(buf,sizeof(buf),stdin); 305 buf[strlen(buf) - 1] = ‘\0‘; 306 307 //init socket 308 sockfd = init_tcp_client_socket(argv[1],argv[2],NULL,NULL); 309 ret = do_task(sockfd,buf); 310 if (ret == -1) 311 break; 312 } 313 314 return 0; 315 }
1 //******服务端****** 2 // 功能: 判断客服端请求的文件 3 // 【1】打开文件,如果只读方式打开失败,协议回送客服端,文件不存在 4 // 如果只读方式打开成功,告诉客户端文件存在 5 // 【2】读取文件写到套接字中去 6 7 8 #include <head.h> 9 10 #define UPLOAD_FILE 1 11 #define DOWNLOAD_FILE 2 12 #define FILE_YEXIST 3 13 #define FILE_NEXIST 4 14 #define LIST_DIR 5 15 #define LIST_OVER 6 16 17 typedef struct 18 { 19 unsigned char type; 20 unsigned char file_name[256]; 21 unsigned char file_type; 22 unsigned int file_size; 23 }__attribute__ ((__packed__))head_t; 24 25 //初始化服务端套接字 26 int init_tcp_server_socket(const char *ip,const char *port) 27 { 28 int ret; 29 int sockfd; 30 struct sockaddr_in server_addr; 31 32 sockfd = socket(AF_INET,SOCK_STREAM,0); 33 if(sockfd < 0){ 34 perror("Fail to socket"); 35 exit(EXIT_FAILURE); 36 } 37 38 server_addr.sin_family = AF_INET; 39 server_addr.sin_port = htons(atoi(port)); 40 server_addr.sin_addr.s_addr = inet_addr(ip); 41 ret = bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)); 42 if(ret < 0){ 43 perror("Fail to bind"); 44 exit(EXIT_FAILURE); 45 } 46 47 listen(sockfd,128);//监听 48 printf("Listen ...\n"); 49 50 return sockfd; 51 } 52 53 //接收 54 int tcp_recv_file(int sockfd,head_t *head) 55 { 56 int n; 57 int fd; 58 int ret; 59 int count = 0; 60 char buf[1024]; 61 //打开文件 62 fd = open(head->file_name,O_WRONLY | O_CREAT | O_TRUNC,0666); 63 if(fd < 0){ 64 fprintf(stderr,"Fail to open %s : %s\n",head->file_name,strerror(errno)); 65 return -1; 66 } 67 68 //接收文件内容 69 while(1) 70 { 71 n = recv(sockfd,buf,sizeof(buf),0); 72 if(n <= 0){ 73 break; 74 } 75 76 ret = write(fd,buf,n);//循环写入 77 if(ret < 0){ 78 perror("Fail to write"); 79 break; 80 } 81 82 count += n; 83 if(count >= head->file_size)//循环跳出条件 84 break; 85 } 86 87 if(count == head->file_size){ 88 printf("Recv file complete\n"); 89 }else{ 90 printf("Recv file uncomplete ,recv %d bytes\n",count); 91 } 92 93 return 0; 94 } 95 96 //发送 97 int tcp_send_file(int sockfd,head_t *head) 98 { 99 int ret; 100 int fd; 101 int n; 102 int count = 0; 103 char buf[1024]; 104 unsigned long total_size; 105 106 fd = open(head->file_name,O_RDONLY);//只读方式打开文件 107 if(fd < 0){ 108 goto error_open; 109 } 110 111 total_size = lseek(fd,0,SEEK_END);//获得文件大小 112 lseek(fd,0,SEEK_SET); //复位 113 114 //文件能打开,说明文件存在,发送协议,给客户端做回复 115 head->type = FILE_YEXIST;i 116 head->file_size = total_size; 117 ret = send(sockfd,head,sizeof(head_t),0); 118 if(ret < sizeof(head_t)){ 119 perror("Fail to send"); 120 close(fd); 121 goto error_send; 122 } 123 124 //发送文件内容 125 while(1) 126 { 127 n = read(fd,buf,sizeof(buf));//循环读入文件到缓冲区 128 if(n <= 0){ 129 break; 130 } 131 132 ret = send(sockfd,buf,n,0);//循环从缓冲区写入文件到套接字 133 if(ret < n){ 134 break; 135 } 136 137 count += n; 138 if(count >= total_size) 139 break; 140 } 141 142 if(count == total_size){ 143 printf("send success!\n"); 144 }else{ 145 printf("send failed ,send %d bytes\n",count); 146 } 147 148 close(fd); 149 return 0; 150 151 error_open://打开只读文件失败,说明文件不存在,则发送协议头,告知客户端文件不存在 152 head->type = FILE_NEXIST; 153 ret = send(sockfd,head,sizeof(head_t),0); 154 if(ret < sizeof(head_t)){ 155 perror("Fail to send"); 156 } 157 158 error_send: 159 return -1; 160 } 161 162 //列出目录下的文件 163 int do_list(int sockfd) 164 { 165 int ret; 166 DIR *pdir; 167 char buf[1024]; 168 head_t *head = (head_t *)buf; 169 struct dirent *pdirent; 170 171 pdir = opendir(".");//打开当前目录 172 if(pdir == NULL){ 173 perror("Fail to opendir"); 174 return -1; 175 } 176 177 while(pdirent = readdir(pdir))//循环读取目录中的文件 178 { 179 //过滤掉隐藏文件 180 if(pdirent->d_name[0] == ‘.‘){ 181 continue; 182 } 183 //文件名写入到协议报头中 184 strcpy(head->file_name,pdirent->d_name); 185 ret = send(sockfd,buf,sizeof(head_t),0); 186 if(ret < 0){ 187 perror("fail to send"); 188 return -1; 189 } 190 } 191 192 //加上报头类型,发送协议给客户端 193 head->type = LIST_OVER; 194 ret = send(sockfd,buf,sizeof(head_t),0); 195 if(ret < 0){ 196 perror("fail to send"); 197 return -1; 198 } 199 200 return 0; 201 } 202 203 //子线程与客户端交互(处理文件的发送和接收) 204 void *do_client(void *arg) 205 { 206 int n; 207 int count = 0; 208 char buf[1024]; 209 int sockfd = *(int *)arg;//强转类型 210 head_t *head = (head_t *)buf; 211 212 free(arg); 213 214 //接收协议 215 while(1) 216 { 217 n = recv(sockfd,buf + count ,sizeof(head_t) - count,0); 218 if(n <= 0){ 219 goto err_recv; 220 } 221 222 count += n; 223 if(count >= sizeof(head_t)) 224 break; 225 } 226 227 switch(head->type) 228 { 229 case UPLOAD_FILE: 230 tcp_recv_file(sockfd,head); 231 break; 232 233 case DOWNLOAD_FILE: 234 tcp_send_file(sockfd,head); 235 break; 236 237 case LIST_DIR: 238 do_list(sockfd); 239 } 240 241 242 err_recv: 243 close(sockfd); 244 pthread_exit(NULL); 245 } 246 247 //接收客户端请求 248 int recv_client_request(int listen_sockfd) 249 { 250 int ret; 251 pthread_t tid; 252 int *pconnect_sockfd; 253 struct sockaddr_in peer_addr; 254 socklen_t addrlen = sizeof(struct sockaddr);//初始化值结果(必须) 255 //创建线程,让每个客户端有一个与之对应的线程 256 while(1){ 257 pconnect_sockfd = (int *)malloc(sizeof(int)); 258 259 *pconnect_sockfd = accept(listen_sockfd,(struct sockaddr *)&peer_addr,&addrlen); 260 if(*pconnect_sockfd < 0){ 261 perror("Fail to accept"); 262 exit(EXIT_FAILURE); 263 } 264 265 //create thread 266 267 printf("--------------------------\n"); 268 printf("connect_sockfd : %d\n",*pconnect_sockfd); 269 printf("Port : %d\n",ntohs(peer_addr.sin_port)); 270 printf("Ip : %s\n",inet_ntoa(peer_addr.sin_addr)); 271 printf("--------------------------\n"); 272 273 ret = pthread_create(&tid,NULL,do_client,pconnect_sockfd); 274 if(ret != 0){ 275 fprintf(stderr,"Fail to pthread_create : %s\n",strerror(ret)); 276 exit(EXIT_FAILURE); 277 } 278 279 pthread_detach(tid);//系统自动回收线程资源 280 } 281 282 return 0; 283 } 284 285 //./tcp_server ip port 286 int main(int argc, const char *argv[]) 287 { 288 int listen_sockfd; 289 290 if(argc < 3){ 291 fprintf(stderr,"Usage : %s <ip> <port>\n",argv[0]); 292 return -1; 293 } 294 295 listen_sockfd = init_tcp_server_socket(argv[1],argv[2]); 296 297 recv_client_request(listen_sockfd); 298 299 return 0; 300 }
标签:
原文地址:http://www.cnblogs.com/yuanxuya/p/5038777.html