整个例子在VS2008下调试通过,测试了不同发送缓冲区大小实现不同传输速度,自己可以调试确定发送缓冲区的大小。
如果需要,发送部分可以修改成多线程模式,可以接收多个客户端的请求。
//发送部分
#include "stdafx.h"
#include<iostream>
#include<winsock2.h>
#include <stdio.h>
#include<ctime>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main()
{
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2), &wsaData)) //初始化WinSock协议栈
{ cout<<"Winsock不能被初始化!";
WSACleanup();
return 0;
}
SOCKET sockSer, sockConn; //注意服务器端必须创建两个套接字
sockSer=socket(AF_INET,SOCK_STREAM,0); //初始化套接字
SOCKADDR_IN addrSer,addrCli; //注意服务器端要创建两个套接字地址
addrSer.sin_family=AF_INET;
addrSer.sin_port=htons(5566);
addrSer.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
bind(sockSer,(SOCKADDR*)&addrSer,sizeof(SOCKADDR)); //绑定套接字
listen(sockSer,5);
int len=sizeof(SOCKADDR);
cout<<"服务器等待客户端的连接……"<<endl;
sockConn=accept(sockSer,(SOCKADDR*)&addrCli,&len); //接受连接,注意返回值
if(sockConn==INVALID_SOCKET)
{
cout<<"服务器接受客户端连接失败!"<<endl;
return 0;
}
else cout<<"服务器接受客户端连接成功!"<<endl;
char fileName[256]="d:\\cf.png";
//缓冲区大小和速度很有关系:太小,速度慢;太大,报错
const int bufferSize=1024*10*20;
char filebuf[bufferSize],OK[3],fsize[50];
/***打开要传输的文件***/
FILE *fp; //创建文件指针
if((fp=fopen(fileName,"rb"))==NULL)
{ //以只读字节型模式打开文件
cout << "不能打开文件: " << fileName << endl;
closesocket(sockConn); //关闭socket,对方等待的recv()函数将返回0
closesocket(sockSer); WSACleanup();
return 0;
} //文件打开失败则退出
/***获取文件长度***/
fseek(fp,0L,SEEK_END); //将文件的位置指针移到文件末尾
long int size=ftell(fp); //获取当前文件位置指针值,该值即为文件长度
fseek(fp,0L,SEEK_SET); //将文件的位置指针移到文件开头
long int fileSize=size;
//fileSize = htonl(size); //将文件长度存入结构变量fileMsg
itoa(fileSize,fsize,10);
send(sockConn, fsize, strlen(fsize)+1, 0); //发送fileName
cout<<fsize<<endl;
/***接收对方发送来的OK信息***/
if (recv(sockConn, OK, sizeof(OK), 0) <= 0)
{
cout << "接收OK失败,程序退出!\n";
closesocket(sockSer); WSACleanup();
return 0;
}
/***发送文件内容***/
int optLen=0;
char optVal=0;
getsockopt(sockConn,SOL_SOCKET,SO_SNDBUF,&optVal,&optLen);
cout<<"缓冲区:"<<optLen<<" 缓冲区: "<<int(optVal)<<endl;
///禁用Nagle算法,在Windows下没什么效果
/*const char flag = 1;
int ret = setsockopt(sockConn, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
if (ret == -1)
cout<<"Couldn't setsockopt(TCP_NODELAY)\n"<<endl;
else
cout<<"setsockopt(TCP_NODELAY) success"<<endl;*/
clock_t t1=clock();
clock_t t2;
if (strcmp(OK, "OK") == 0)
{
while(!feof(fp))
{ //当文件没有到末尾时
size=fread(filebuf,1,sizeof(filebuf),fp); //每次读1000字节
send(sockConn, filebuf, size, 0); //每次写size个字节
}
t2=clock();
cout << "文件发送完毕"<<t2-t1<<endl; //显示传输完成
fclose(fp);
} //关闭文件
closesocket(sockSer);
WSACleanup();
system("pause");
return 0;
}
//接收部分
#include "stdafx.h"
#include<iostream>
#include<winsock2.h>
#include <stdio.h>
#include "direct.h" //_mkdir()函数需要
#pragma comment(lib,"ws2_32.lib")
#include <ctime>
using namespace std;
int main()
{
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2), &wsaData)) {
cout<<"Winsock不能被初始化!";
WSACleanup();
return 0; }
SOCKET sockCli; //创建套接字sockCli
sockCli=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addrSer; //客户端只要创建一个套接字地址
addrSer.sin_family=AF_INET;
addrSer.sin_port=htons(5566);
addrSer.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
int res=connect(sockCli,(SOCKADDR*)&addrSer, sizeof(SOCKADDR));
if(res){
cout<<"客户端连接服务器失败"<<endl;
return -1;
}
else{
cout<<"客户端连接服务器成功"<<endl;
}
char sendbuf[256], recvbuf[256];
long int filelen;
char filedir[200]= "D:\\TANG\\"; //指定接收到的文件的保存目录
char ok[3]="OK",fsize[50];
char fileBuffer[1000];//接收文件数据的缓冲区
/***创建文件的保存目录***/
_mkdir(filedir); //_mkdir()用于创建文件夹
/***接收文件名及文件长度信息***/
if((filelen=recv(sockCli,fsize,sizeof(fsize),0))<=0)
{
cout<<"未接收到文件名字及文件长度!\n";
closesocket(sockCli); WSACleanup();
return 0;
}
filelen=atol(fsize);
/***创建文件准备接收文件内容***/
char filename[256]="e:\\cf.png";
FILE *fp; //创建文件指针
if((fp=fopen(filename,"wb"))==NULL)
{//以只写方式打开文件
cout<<"不能打开文件:"<<filename<<endl;
closesocket(sockCli);
WSACleanup();
return 0;
} //文件打开失败则退出
double fileSize=filelen;
cout<<filelen;
send(sockCli,ok,sizeof(ok),0); //发送接收文件数据的确认信息
/***接收文件数据并写入文件***/
long int size=0; //接收到的数据长度
clock_t t1=clock();
clock_t t2;
do
{
size=recv(sockCli,fileBuffer,sizeof(fileBuffer),0);
fwrite(fileBuffer,1,size,fp); //写入文件,每次写size字节
filelen-=size;
}while(size!=0 && filelen>0); //循环条件是size!=0 && filelen>0
/***文件传输完成结束程序***/
t2=clock();
cout<<"接收文件"<<filename<<"完毕!\n"<<t2-t1<<endl;
double t=1024*1024*(t2-t1)/1000.0;
cout<<"speed:"<<fileSize/t<<"MB/S"<<endl;
fclose(fp);
while(1)
{
cout<<"客户端说:>";
cin>>sendbuf;
if(strcmp(sendbuf,"bye")==0){
break;}
send(sockCli,sendbuf,strlen(sendbuf)+1,0);
if(recv(sockCli,recvbuf,256,0)>0)
cout<<"服务器说:>"<<recvbuf<<endl;
else {cout<<"服务器已关闭连接"<<endl;
break;}
}
closesocket(sockCli);
WSACleanup();
return 0;
}