Linux利用socket實現兩臺pc之間的資料傳輸功能,包括windows到linux,UDP實現
阿新 • • 發佈:2019-02-04
makefile 和TCP一樣,參見上一篇博文
客戶端和服務端主函式也和上一篇的tcp是一樣的,同樣參考上一篇博文,這裡只是修改了pub.c的檔案了
/* * pub.c * * Created on: 2016年7月14日 * Author: Administrator */ #ifdef WIN #include <WinSock2.h> #else #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include <errno.h> #include <string.h> #define SOCKET int #endif #include <stdio.h> #include "pub.h" #define BUFSIZE 262144 //1024 * 256 void getfilename(const char *filename, char *name) { int len = strlen(filename); int i; for (i = (len - 1); i >= 0; i--) { if ((filename[i] == '\\') || (filename[i] == '/')) { break; } } strcpy(name, &filename[i + 1]); } int init_socket() { // 如果是windows,執行如下程式碼 #ifdef WIN WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 1); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return -1; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return -1; } #endif return 0; } SOCKET create_send_socket()// 建立傳送資料的udp socket { if (init_socket() == -1) return 0; SOCKET st = socket(AF_INET, SOCK_DGRAM, 0);// 建立UDP socket if (st == 0) return 0; // 如果建立socket失敗,返回0 return st; // udp socket建立成功,返回socket描述符 } SOCKET create_recv_socket(int port) { SOCKET st = socket(AF_INET, SOCK_DGRAM, 0);// 建立UDP socket if (st == 0) return 0; struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(st, (struct sockaddr*)&addr, sizeof(addr)) == -1) { printf("bind failed %s\n", strerror(errno)); return 0; } return st;// udp } // 連線到hostname指定的IP地址和port指定的埠號 int send_work(const char *hostname, int port, const char *filename) { SOCKET st_send = create_send_socket();// 建立傳送資料的UDP Socket SOCKET st_recv = create_recv_socket(port + 1);// 建立接受資料的UDP Socket if (st_send == 0) // 建立失敗,函式返回 { return 0; } if (st_recv == 0) // 建立失敗,函式返回 { return 0; } FILE *fd = fopen(filename, "rb"); // 以只讀方式開啟filename指定的檔案 if (fd == NULL) // 如果開啟檔案失敗,函式返回 { printf("open %s failed %s\n", filename, strerror(errno)); return 0; } char *buf = malloc(BUFSIZE); // 申請一個緩衝區,存放接收到的檔案內容 memset(buf, 0, BUFSIZE); // 從完整路徑名中解析出檔名稱 getfilename(filename, buf); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(hostname); // 客戶端第一次給server端傳送檔名 size_t rc = sendto(st_send, buf, strlen(buf), 0, (struct sockaddr *)&addr, sizeof(addr)); // 客戶端第一次給server端傳送的資料為要傳遞的檔名 if (rc <= 0) { printf("send failed %s\n", strerror(errno)); } else { struct sockaddr_in client_addr; #ifdef WIN int len = 0; #else unsigned int len 0; #endif len = sizeof(client_addr); memset(&client_addr, 0, sizeof(client_addr)); memset(buf, 0, BUFSIZE); if (recvfrom(st_recv, buf, BUFSIZE, 0, (struct sockaddr *)&client_addr, &len) <= 0) // 接受來自server端的回覆 { printf("recv failed %s\n", strerror(errno)); } else { if (strncmp(buf, "OK", 2) == 0) { while(1) { memset(buf, 0, BUFSIZE); rc = fread(buf, 1, BUFSIZE, fd); if (rc <= 0) { break;// } else { rc = sendto(st_send, buf, rc, 0, (struct aockaddr *)&addr, sizeof(addr)); if (rc <= 0) { printf("send failed %s\n", strerror(errno)); break; } } } } memset(buf, 0, BUFSIZE); // 連發128位元組0,代表檔案傳送完畢 rc = sendto(st_send, buf, 128, 0, (struct aockaddr *)&addr, sizeof(addr)); } } fclose(fd); free(buf); #ifdef WIN closesocket(st_send); closesocket(st_recv); WSACleanup(); #else close(st_send); close(st_recv); #endif return 1; } // server端socket在port指定的斷口上listen,接收來自client傳送的檔案 int recv_work(int port) { SOCKET st_send = create_send_socket();// 建立傳送資料的UDP Socket SOCKET st_recv = create_recv_socket(port);// 建立接受資料的UDP Socket if (st_send == 0) // 建立失敗,函式返回 { return 0; } if (st_recv == 0) // 建立失敗,函式返回 { return 0; } char *buf = malloc(BUFSIZE); FILE *fd = NULL; #ifdef WIN int len = 0; #else unsigned int len = 1; #endif struct sockaddr_in client_addr; len = sizeof(client_addr); memset(&client_addr, 0, sizeof(client_addr)); memset(buf, 0, BUFSIZE); // 接收來自client的資料,客戶端第一次傳送的檔名 size_t rc = recvfrom(st_recv, buf, BUFSIZE, 0, (struct sockaddr *)&client_addr, &len); if (rc <= 0) { printf("recv failed %s\n", strerror(errno)); } else { printf("receiving %s\n", buf); fd = fopen(buf, "wb");// 以只寫方式開啟檔案 if (fd == NULL) { printf("open %s failed %s\n", buf, strerror(errno)); } else { client_addr.sin_port = htons(port + 1); memset(buf, 0, BUFSIZE); strcpy(buf, "OK"); rc = sendto(st_send, buf, strlen(buf), 0, (struct *)&client_addr, sizeof(client_addr)); // 回覆客戶端,同意接收檔案 if (rc <= 0) { printf("send failed %s\n", strerror(errno)); } while (1) { memset(buf, 0, BUFSIZE); rc = recvfrom(st_recv, buf, BUFSIZE, 0, (struct *)&client_addr, &len);// 迴圈接收來自client的資料,資料為傳送檔案的內容 char tmp[128]; memset(tmp, 0, sizeof(tmp)); if (memcmp(buf, tmp, sizeof(tmp)) == 0) { break; } if (rc <= 0)// 如果client連線斷開,代表檔案傳遞完成,或者網路意外中斷,迴圈break { printf("recv failed %s\n", strerror(errno)); break; } else { fwrite(buf, 1, rc, fd);// 將從client端收到的內容寫入檔案 } } } } if (fd) fclose(fd); free(buf); #ifdef WIN closesocket(st_send); closesocket(st_recv); WSACleanup(); #else close(st_send); close(st_recv); #endif return 1; }