環境:win11,VS2019
分為服務端和客戶端,實現文件的傳輸
好吧確實是有點本末倒置,應該先上消息的互傳,再進行文件的傳輸,這是因為在學習消息的傳輸時沒有找到合適的講得明白的教程
現在再回頭看消息傳輸,其實也是一樣的步驟,只不過把文件改成了字符串而已,應該是會簡單一點的。
廢話不多說,直接上代碼,盡量在代碼里多加點注釋叭
//服務端
/*寫在前面:
眾所周知,TCP在進行傳輸的時候需要三次握手,很幸運,這些東西windows都封裝好了,不用我一個初學者再寫(我也不會2333)
於是,需要注意的就只有網絡通信本身了。
怎樣才能定位到對方的計算機和對方的對應通訊程序呢?
IP地址用來定位計算機,每一個程序所對應的有一個1~32768的一個數字稱為端口,用這個數字來定位計算機內部眾多的程序。
下文的注釋把套接字比喻為電話機,可能比較明了。
*/
#include<cstdio> #include<winsock2.h> #include<cstring> #include<Windows.h>
#pragma comment(lib,"ws2_32.lib")//鏈接lib庫,
using namespace std; int main() { //初始化套接字(winsocket)
WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData);//MAKEWORD,把兩個32位int綁定為一個數,(版本號) //安裝電話機(創建套接字)PF_INET=Ipv4
SOCKET hServSock = socket(PF_INET, SOCK_STREAM, 0);//IPv4協議,流式套接字,0表示TCP //綁定電話號碼和分機號(ip&端口)
SOCKADDR_IN servAddr;//定義一個套接字(結構體) memset(&servAddr, 0, sizeof(servAddr));//清空結構體servAddr內的東西
servAddr.sin_family = AF_INET;//服務端,所以需要的是地址簇(family),AF_INET表示IPv4協議 servAddr.sin_addr.s_addr = htonl(INADDR_ANY);//使用自身的IP地址。htonl:將主機的無符號長整形數轉換成網絡字節順序;INADDR_ANY表示本機IP
servAddr.sin_port = htons(7777);//0~1024不能用;確定端口號;htons轉化類型
bind(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr));//把電話機和電話號碼綁定,即套接字和存儲地址和端口號的結構體綁定。 //監聽,拿起電話聽筒聽對面是否說話
listen(hServSock, 5);//最多5台電話 //發現監聽對象,接電話 //獲得對方的ip,端口號
SOCKADDR_IN clntAddr; int clntAdrSz = sizeof(clntAddr); SOCKET hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &clntAdrSz);//創建 //說話 //看一下對方的ip地址 //printf("%s", inet_ntoa(clntAddr.sin_addr));
char buf[1025]={0}; recv(hClntSock,buf,1024,0);//先接受文件名 //printf("%s\n", buf);
FILE* fp = fopen(buf, "wb");//用文件名創造二進制文件
int bytes; while ((bytes = recv(hClntSock, buf, 1024, 0)) > 0)//每次接受1024個字節存在buf里 { fwrite(buf, 1, bytes,fp);//把buf里的東西存在文件中 } fclose(fp);//完成,關閉文件 closesocket(hClntSock);//銷毀套接字 closesocket(hServSock); //空文件,接收內容 WSACleanup();//回收套接字
return 0; }
/*寫在前面
有了前面的服務端,會發現,其實客戶端和服務端長得是很像的
話不多說,直接開始
*/
#include<cstdio> #include<winsock2.h> #include<cstring> #pragma comment(lib,"ws2_32.lib")
using namespace std; int main() { //初始化套接字(winsocket) WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); //打電話 SOCKET hClntSOCK = socket(PF_INET,SOCK_STREAM ,0);//創建流式套接字TCP //127.0.0.1(本機)7777(端口號) SOCKADDR_IN clntAddr; memset(&clntAddr,0,sizeof(clntAddr));//同服務端,清空結構體 clntAddr.sin_family=AF_INET; clntAddr.sin_addr.s_addr=inet_addr("127.0.0.1"); clntAddr.sin_port=htons(7777); //連接 connect(hClntSOCK,(SOCKADDR*)&clntAddr,sizeof(clntAddr)); //發送一個文件名 send(hClntSOCK,"1.mp4",1024,0); FILE* fp = fopen("1.mp4", "rb");//打開文件,只讀 char buf[1024] = { 0 }; int bytes; while ((bytes = fread(buf, 1, 1024, fp) )> 0)//讀取文件內容,每次一個1024字節 { send(hClntSOCK, buf, 1024, 0);//把buf里存的東西send給服務端 } fclose(fp);//傳輸完成,關閉文件 closesocket(hClntSOCK); WSACleanup();//回收套接字 return 0; }
(To be continued)