傳檔案通用(結構體)
阿新 • • 發佈:2022-04-04
通過結構體傳檔案
伺服器程式碼:
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/ip.h> #include <sys/stat.h> #include <fcntl.h> #include<string.h> #include <sys/stat.h> #define N 512 //每次上傳一個結構體 typedef struct file { int len_max;//檔案最大長度 int len;//本次傳輸的長度 char buf[N];//傳輸的內容 }File; //傳輸顯示 void bar(int x,int max) { system("clear"); int i,k; k = x*1.0/max*100; printf("/"); for(i = 0; i < k/5; i++) { printf("#"); } for(i = 0; i < 20-k/5; i++) { printf("*"); } printf("/%d%%\n",k); //延時只是為了顯示效果沒啥用可以自己調 usleep(50000); } //套接字初始化 //三個引數分別為IP、埠號、允許最大連線 int tcp_server_init(char *ip, int port, int backlog) { //建立套接字檔案打通軟體和硬體的關節 int skt = socket(AF_INET, SOCK_STREAM, 0); if(-1== skt) { printf("socker error\n"); return -1; } //將IP和埠號存入結構體 struct sockaddr_in sddr; sddr.sin_family = AF_INET; sddr.sin_port = htons(port); sddr.sin_addr.s_addr = inet_addr(ip); //將套接字和IP、埠號進行繫結 int ret = bind(skt, (struct sockaddr *)&sddr, sizeof(sddr)); if(-1 == ret) { printf("bind error\n"); return -1; } //監聽套接字並設定最大連結數量 ret = listen(skt, backlog); if(-1 == ret) { printf("listen error\n"); return -1; } puts("listen...."); return skt; } //連線函式 //引數是開啟的套接字檔案描述符 int tcp_wait_connect(int skt) { struct sockaddr_in cddr; int len = sizeof(cddr); int nfd = accept(skt, (void *)&cddr, &len); if(-1 == nfd) { perror("accept error\n"); return -1; } return nfd; } int main(int argc, char *argv[]) { char tmp[3] = {'\0'}; int skt = tcp_server_init("0.0.0.0", 6666, 10); int nfd = tcp_wait_connect(skt); File file = {'\0'}; read(nfd, tmp, sizeof(tmp)); int fr = open(argv[1], O_RDONLY); if(-1 == fr) { printf("open error\n"); return -1; } //計算檔案大小 struct stat str; stat(argv[1], &str); file.len_max = str.st_size; int count = 0; if(0 == strcmp(tmp,"go")) { while(1) { file.len = read(fr, file.buf, sizeof(file.buf)); count = file.len + count; bar(count, file.len_max); write(nfd, &file, sizeof(file)); if(0 == file.len) { break; } } } printf("上傳完成!\n"); close(fr); close(skt); close(nfd); return 0; }
客戶端程式碼:
#include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <arpa/inet.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> //一次接收的位元組數建議不要超過512且需要與伺服器一次上傳的位元組數一至 #define N 512 //每次接收一個結構體 typedef struct file { int len_max;//檔案最大長度 int len;//本次傳輸的長度 char buf[N];//傳輸的內容 }File; //傳輸顯示 void bar(int x,int max) { system("clear"); int i,k; k = x*1.0/max*100; printf("/"); for(i = 0; i < k/5; i++) { printf("#"); } for(i = 0; i < 20-k/5; i++) { printf("*"); } printf("/%d%%\n",k); //延時只是為了顯示效果沒啥用可以自己調 usleep(50000); } int main(int argc, char *argv[]) { //建立套接字 int skt = socket(AF_INET, SOCK_STREAM, 0); if(-1 == skt) { printf("socket error\n"); return -1; } //將IP、埠號存入結構體 struct sockaddr_in sddr; sddr.sin_family = AF_INET; sddr.sin_port = htons(atoi(argv[2])); sddr.sin_addr.s_addr = inet_addr(argv[1]); //繫結 int ret = connect(skt, (struct sockaddr *)&sddr, sizeof(sddr)); if(-1 == ret) { printf("connect error\n"); return -1; } //識別符號 char tmp[3] = {'\0'}; File file = {'\0'}; //建立或開啟一個檔案存放下載的內容 int fr = open(argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0666); if(-1 == fr) { printf("open error\n"); return -1; } printf("要開始嗎?"); int count = 0; //輸入指定字元開始下載 fgets(tmp,sizeof(tmp),stdin); write(skt, tmp, 2); while(1) { read(skt, &file, sizeof(file)); if(0 == file.len) { break; } count = file.len + count; bar(count, file.len_max); write(fr, file.buf, file.len); } printf("下載完成!\n"); close(skt); close(fr); return 0; }
Makefile
APP: gcc -g server.c -o server gcc -g app.c -o app R1: ./server qy.jpg R2: ./app 192.168.10.159 6666 wf.jpg