想弄个传文件程序。
服务器先启动,等待接收文件,客户端后启动用来发送文件。双方用TCP连接好之后客户端先发送一个 LARGE_INTEGER 变量,变量中保存的是文件的大小。这个文件是光盘的压缩文件,右键属性显示1.48G。
发送完大小之后双方开始用 while  循环发送和接收,程序运行了大概20秒之后,双方都各自阻塞在自己的 recv 函数。下面客户端发送完文件大小之后,服务器就进入 while 循环开始接收数据,把收到的数据写入文件,在给客户 send 回去 WriteFile 了多少字节, 客户端收到服务器 WriteFile 多少字节之后调用文件的 SetFilePointerEx,以便下次从那继续发送下面是服务器端和客户端的代码和运行结果图
//服务器端(接收文件)#include<Windows.h>
#include<iostream>
using namespace std;const int iOneMBufferSize = 1024*1024;
char buffer[iOneMBufferSize];//一兆空间
void main()
{
setlocale(LC_ALL, "chs");
WSAData data;
WSAStartup(MAKEWORD(2,2),&data);
SOCKET s1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
bind(s1, (SOCKADDR*)&addr, sizeof(addr));
listen(s1,100);
int len = sizeof(addr);
SOCKET s2 = accept(s1,(SOCKADDR*) &addr,&len);
if( s2 != INVALID_SOCKET )
wcout<<L"***** 有客户端连入 *****"<<endl; LARGE_INTEGER i64FileSize, i64FileSizeCopy;
recv(s2,(char*)&i64FileSize, sizeof(i64FileSize), 0);
i64FileSizeCopy.QuadPart = i64FileSize.QuadPart;
wcout<<L"**** 文件大小是 "<< i64FileSize.QuadPart <<L"字节, 文件保存在C盘根目录下 ****"<<endl;
HANDLE hFile = CreateFile(L"C:\\接收文件.rar",
GENERIC_READ | GENERIC_WRITE,//读写权限
0,//不共享
0,//默认安全描述符
OPEN_ALWAYS,//存在就打开,不存在就创建
0,//Flags and Attributes
0);//hFileTemplate
if(hFile==INVALID_HANDLE_VALUE)
wcout<<L"**** 文件创建失败 ****"<<endl;
DWORD dwNumBytes;
while( i64FileSize.QuadPart>0)//这里的一堆wcout是为看出阻塞在哪
{
ZeroMemory(buffer, iOneMBufferSize);
wcout<<L"服务器准备接收文件"<<endl;
int size = recv(s2, buffer, iOneMBufferSize, 0);
wcout<<L"服务器收完文件"<<endl;
wcout<<L"服务器准写文件"<<endl;
WriteFile(hFile, buffer, size, &dwNumBytes, 0);
wcout<<L"服务器写完文件"<<endl; wcout<<L"服务器准备发送 dwNumBytes"<<endl;
send(s2, (char*)&dwNumBytes, sizeof(DWORD), 0);
wcout<<L"服务器发完 dwNumBytes"<<endl; i64FileSize.QuadPart -= dwNumBytes; // wcout<<L"接收中\t";
}
wcout<<endl<<L"****接收完毕****"<<endl;
while(1)
{}
}//客户端(发送文件)
#include<Windows.h>
#include<iostream>
using namespace std;const int iOneMBufferSize = 1024*1024;
char buffer[iOneMBufferSize];//一兆空间
void main()
{
setlocale(LC_ALL, "chs");
WSAData data;
WSAStartup(MAKEWORD(2,2),&data);
SOCKET s1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
char ip[100];
ZeroMemory(ip,100);
wcout<<L"输入对方IP: ";
cin>>ip;//这里输入 127.0.0.1
addr.sin_addr.S_un.S_addr = inet_addr(ip);
int e = connect(s1, (SOCKADDR*)&addr, sizeof(addr));
if(e==-1)
wcout<<L"connect 函数失败"<<endl; HANDLE hFile = CreateFile(L"C:\\Users\\ys\\Desktop\\Visual C++开发入行真功夫光盘二次.rar",
GENERIC_READ | GENERIC_WRITE,//读写权限
0,//不共享
0,//默认安全描述符
OPEN_ALWAYS ,//存在就打开,不存在就创建
0,//Flags and Attributes
0);//hFileTemplate
if(hFile==INVALID_HANDLE_VALUE)
wcout<<L"**** 文件读取失败 ****"<<endl; LARGE_INTEGER i64FileSize, i64FileSizeCopy;
GetFileSizeEx(hFile, &i64FileSize);
i64FileSizeCopy.QuadPart = i64FileSize.QuadPart;
wcout<<L"共需发送 " << i64FileSize.QuadPart <<L"字节" <<endl;
send(s1, (char*)&i64FileSize.QuadPart, sizeof(i64FileSize.QuadPart), 0);
DWORD dwNumBytes; while( i64FileSize.QuadPart >0 )//这里的一堆wcout是为看出阻塞在哪
{
ZeroMemory(buffer, iOneMBufferSize);
wcout<<L"客户端准备读文件"<<endl;
ReadFile(hFile, buffer, iOneMBufferSize, &dwNumBytes, 0);
wcout<<L"客户端读完文件"<<endl;
wcout<<L"客户端准备发送文件"<<endl;
send(s1, buffer, dwNumBytes, 0);
wcout<<L"客户端发完文件"<<endl; DWORD size;
wcout<<L"客户端准备接收服务器返回的 dwNumBytes"<<endl;
recv(s1, (char*)&size, sizeof(DWORD), 0);
wcout<<L"客户端收完服务器返回的 dwNumBytes"<<endl; LARGE_INTEGER move;
move.QuadPart = size;
wcout<<L"客户端准备设置文件指针"<<endl;
SetFilePointerEx(hFile, move, 0, FILE_CURRENT);
wcout<<L"客户端设完文件指针"<<endl;
i64FileSize.QuadPart -= size; wcout<<L"发送中\t";
}
wcout<<endl<<L"****发送完毕****"<<endl;
while(1)
{}
}

解决方案 »

  1.   

    至于你说的时间问题,我也想过,后来把这种想法否决了。
    假设,新来的数据已经到达网卡或内存,而我这里还在执行上一轮的 WriteFile,那完全可以在下一次循环到 recv 的时候在去读取数据,因为我这里都是同步的,而且没有采用任何五花八门的 flags 标志,因为没有使用 flags 标志所以网卡或内存中的数据会为我保留,只要过一会读取就好了。
    况且我曾经试验过下面的做法:
    接收端等待一个 cin 操作,而在 cin。之前对方早已经发送来了数据,我 cin 之后在去 recv 完全是正常的。所以时间不是问题。
      

  2.   

    是阻塞,通常非阻塞我都习惯自己调用 CreateThread。 你说的一一对应是不可能了,一是因为输出太多,二是滚屏都滚过去了
      

  3.   

    你百度 TransmitFile 吧,这里也说不完啊,
      

  4.   

    int size = recv(s2, buffer, iOneMBufferSize, 0); 
    send(s1, buffer, dwNumBytes, 0); 这里你需要判断发送和接收函数的返回结果, 有许多情况会导致返回SOCKET_ERROR, 而且不同情况处理也不同, 有些如WSAEWOULDBLOCK需要重发(收)数据详情请看MSDN关于这两个函数的介绍, 特别是re部分。
    http://msdn.microsoft.com/en-us/library/ms740149(VS.85).aspx
      

  5.   

    函数返回结果不用判断,TCP会保证不丢失数据。 SOCKET_ERROR也不用担心,只要程序在运行是时候你不关闭就不会返回 SOCKET_ERROR
      

  6.   

    send和recv都要判断返回值,大于0才表示成功,继续下面的操作。另外,你可以用select或WSAAsynSelect判断什么时候可以recv,看看这的socket例子:
    http://download.csdn.net/detail/geoff08zhang/4571358
      

  7.   

    奇怪,又是类似的问题。再说一次,网络编程不同于函数调用。比如
    发送100字节->等结果接收50字节->发送结果这不就乱套了吗?你这种设计还有很多问题!比如你发送的结果,到接收方根本就不对,很有可能重复,比如像我上面说的例子。
      

  8.   


    请问你有好好看MSDN么?  不要想当然, MSDN上列出的那么多可能的错误你以为是白给的么?  只是你没怎么用没碰到而已