經常在CSDN貼吧看見很多關於網絡之間傳輸的例子(比如傳輸截屏文件),所以很想寫一個作為學習。
此程序設定很簡單,就是在本地傳輸。當然,要擴展到網絡也很簡單,改個ip就ok了。
基本思路:
雙方遵循一個包頭格式,根據包頭確定之後的操作。
服務器代碼:
[cpp]
#include <string>
#include <io.h>
#define PORT 6666
struct PacketHeader
{
char code[10]; // 指令:"EOF"=斷開連接 "PIC"=接收圖片
char name[50]; // 名字:包括後綴
LONG32 size; // 大小:字節
PacketHeader()
{
memset(code,0,sizeof(code));
memset(name,0,sizeof(name));
size = 0;
}
};
// 在本地傳輸圖片
void server()
{
WSADATA wd;
int ret = WSAStartup(MAKEWORD(2,2),&wd);
if(ret != 0)
{
cout<<"Initialize Winsock Failed! "<<GetLastError()<<endl;;
return;
}
cout<<"WSAStartup OK"<<endl;
sockaddr_in addr_serv,addr_cli;
int sock_listen,sock_accept;
try{
sock_listen = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sock_listen == SOCKET_ERROR)
{
cout<<"create socket failed! "<<GetLastError()<<endl;
throw 1;
}
cout<<"socket OK"<<endl;
memset((void*)&addr_serv,0,sizeof(sockaddr));
addr_serv.sin_family = AF_INET;
addr_serv.sin_addr.S_un.S_addr = INADDR_ANY;
addr_serv.sin_port = htons(PORT);
ret = bind(sock_listen,(sockaddr*)&addr_serv,sizeof(addr_serv));
if(ret != 0)
{
cout<<"bind failed! "<<GetLastError()<<endl;
throw 2;
}
cout<<"bind OK"<<endl;
ret = listen(sock_listen,1);
if(ret != 0)
{
cout<<"listen failed! "<<GetLastError()<<endl;
throw 2;
}
cout<<"listen OK"<<endl;
int addrlen = sizeof(addr_cli);
sock_accept = accept(sock_listen,(sockaddr*)&addr_cli,&addrlen);
if(sock_accept == INVALID_SOCKET)
{
cout<<"accept failed! "<<GetLastError()<<endl;
throw 2;
}
cout<<"accept OK"<<endl;
closesocket(sock_listen); //停止監聽
while(true)
{
cout<<"輸入:(EOF表示斷開連接,文件名表示發送文件,例如sumos.txt)"<<endl;
string input;
cin>>input;
if(input.compare("EOF") == 0)
{
PacketHeader ph;
strcpy_s(ph.code,"EOF");
send(sock_accept,(const char*)&ph,sizeof(ph),0);
break;
}
else
{
FILE* fp = NULL;
fopen_s(&fp,input.c_str(),"rb");
if(fp == NULL)
{
cout<<"打開失敗"<<endl;
continue;
}
else
{
LONG32 sz = _filelength(_fileno(fp));
cout<<"文件打開成功,大小:"<<sz<<" Bytes"<<endl;
PacketHeader ph;
strcpy_s(ph.code,"PIC");
strcpy_s(ph.name,input.c_str());
ph.size = sz;
send(sock_accept,(const char*)&ph,sizeof(ph),0);
cout<<"已發送頭部信息"<<endl;
int nSend = 0;
char buffer[1024];
while(nSend < sz)
{
int nBytes = fread(buffer,sizeof(char),1024,fp);
if(nBytes <= 0)
break;
send(sock_accept,buffer,nBytes,0);
cout<<"已發送 "<<nBytes<<" Bytes"<<endl;
nSend += nBytes;
}
cout<<"總計發送 "<<nSend<<" Bytes"<<endl;
fclose(fp);
}
}
}
closesocket(sock_accept);
}catch(int which){
if(which == 2)
closesocket(sock_listen);
if(which == 3)
closesocket(sock_accept);
}
WSACleanup();
}
客戶端代碼:
[cpp]
#include <WinSock.h>
#pragma comment(lib,"ws2_32.lib")
#define IP "127.0.0.1"
#define PORT 6666
struct PacketHeader
{
char code[10]; // 指令:"EOF"=斷開連接 "PIC"=接收圖片
char name[50]; // 名字:包括後綴
LONG32 size; // 大小:字節
PacketHeader()
{
memset(code,0,sizeof(code));
memset(name,0,sizeof(name));
size = 0;
}
};
void client()
{
WSADATA wd;
int ret = WSAStartup(MAKEWORD(2,2),&wd);
if(ret != 0)
{
cout<<"Initialize Winsock Failed! "<<GetLastError()<<endl;;
return;
}
cout<<"WSAStartup OK"<<endl;
sockaddr_in addr_serv;
int sock;
try{
sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sock == SOCKET_ERROR)
{
cout<<"create socket failed! "<<GetLastError()<<endl;
throw 1;
}
cout<<"socket OK"<<endl;
memset((void*)&addr_serv,0,sizeof(sockaddr));
addr_serv.sin_family = AF_INET;
addr_serv.sin_addr.S_un.S_addr = inet_addr(IP);
addr_serv.sin_port = htons(PORT);
ret = connect(sock,(sockaddr*)&addr_serv,sizeof(addr_serv));
if(ret == SOCKET_ERROR)
{
cout<<"connect failed! "<<GetLastError()<<endl;
throw 2;
}
cout<<"connect OK"<<endl;
char buffer[1024];
while(true)
{
int nRecv = recv(sock,buffer,1024,0);
if(nRecv <= 0)
continue;
else if(nRecv == sizeof(PacketHeader))
{
PacketHeader ph;
memcpy_s(&ph,sizeof(ph),buffer,nRecv);
if(strcmp(ph.code,"EOF") == 0)
break;
else if(strcmp(ph.code,"PIC") == 0)
{
cout<<"文件名:"<<ph.name<<",大小:"<<ph.size<<endl;
FILE* fp = NULL;
fopen_s(&fp,ph.name,"wb");
if(fp == NULL)
{
cout<<"創建文件失敗"<<endl;
break;
}
else
{
nRecv = 0;
while(nRecv < ph.size)
{
int nBytes = recv(sock,buffer,1024,0);
if(nBytes <= 0)
break;
cout<<"已接收 "<<nBytes<<" Bytes"<<endl;
fwrite(buffer,sizeof(char),nBytes,fp);
nRecv += nBytes;
}
cout<<"共接收 "<<nRecv<<" Bytes"<<endl;
fclose(fp);
}
}
else
{
cout<<"頭部信息錯誤"<<endl;
break;
}
}
else
{
buffer[nRecv] = '\0';
cout<<buffer<<endl;
}
}
closesocket(sock);
}catch(int which){
if(which == 2)
closesocket(sock);
}
WSACleanup();
}
運行截圖: