套接字文件传输例子

82 篇文章 0 订阅

整个例子在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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值