使用Wininet API上传文件到Web Server。它分为客户端和服务端两块,客户端负责连接服务器,发送数据给服务端;服务端负责接收数据,保存。
首先看客户端:
在这里,需要稍微解释下URL的组成。举个例子:http://myWebServer:8080/Handler/FileUploader.aspx
其中 "myWebServer"为Server Host Name,它用来表示服务器的IP地址。
“8080”是该服务器对http开发的端口号,如不指定的话,默认为80
“/Handler/FileUploader.aspx”就是这个URL的UrlPath了
使用Wininet API同服务器打交道,知道这么多久可以了,下面看怎么编写客户端代码。其实它的步骤是很死的,只要按固定套路使用就可以了。
1. 用 InternetOpen 创建一个表示该次连接的Internet句柄
HINTERNET hInternet = ::InternetOpen(_T("Sample String"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
2. 用 InternetConnect 与指定服务器连接,获得本次连接句柄
// hInternet就是InternetOpen返回的句柄
// szServerHostName就是上面例子URL中的“myWebServer”
// nPort是上例的8080,NULL的话表示默认(80)
HINTERNET hConnection = ::InternetConnect(hInternet, szServerHostName, nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
3. 连接成功后,下面就开始发送请求,告诉服务器,我要上传文件了。
// szUrlPath就是上例中的“/Handler/FileUploader.aspx”,注意,最前面的"/"不能省略的。
// accept是一个LPCTSTR数组,表示该URL接受的文件类型。可以用:
// LPCTSTR accept[] = {
// _T("*/*"),
// NULL
// };
// 表示任何类型
HINTERNET hRequest = ::HttpOpenRequest(hConnection, _T("POST"), szUrlPath, NULL, NULL, accept, 0, INTERNET_FLAG_EXISTING_CONNECT|INTERNET_FLAG_NO_AUTO_REDIRECT|INTERNET_FLAG_HYPERLINK);
INTERNET_BUFFERS ib;
memset(&ib, 0, sizeof(INTERNET_BUFFERS));
ib.dwStructSize = sizeof(INTERNET_BUFFERS);
ib.dwBufferTotal = dwTotalSize; //这里是你要传送数据的总大小,比如一个文件的大小::GetFileSize(hFile, 0)
ib.dwBufferLength = dwBufSize; //分次上传的话,每次上传数据的大小,比如4里面的dwBufSize
::HttpSendRequestEx(hRequest, &ib, 0, HSR_INITIATE, 0));
4. 请求发送成功后,就可以传送数据了,传送数据使用的是::InternetWriteFile这个API
DWORD dwBufSize = 1024*1024; //1M
TCHAR* buffer = new TCHAR[dwBufSize];
DWORD dwRead;
::InternetWriteFile(hRequest, buffer, dwBufSize, &dwRead);
这样就把数据发送到服务端了。
5. 紧接着,客户端需要调用HttpEndRequest()等待服务器处理。这个时候,客户端的执行实际上是停止在这里的,只有当服务段接受完数据,完成处理后,客户端才接着执行下去。
6. 下面就是释放前面申请的句柄和内存了。
以上是客户端向服务器发送数据的全部过程了,如果想传送文件的话,需要在4里面,用一个循环,将文件数据不断读取到buffer里,并用InternetWriteFile发送出去。
服务端:
服务端就负责接收数据了,以下是C# asp.net的样例。
其实,也就是用Request不断从管道里读取上传的数据。
http://myWebServer:8080/Handler/FileUploader.aspx的cs文件
FileUploader.cs文件
public class FileUpload : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Stream input = Request.InputStream;
if (input.Length > 0)
{
String filepath = MapPath("~/Temp/UploadedFile.dat");
using (FileStream output = File.Create(filepath))
{
byte[] buffer = new byte[1024];
int nTotalBytesWritten = 0;
int nRead = input.Read(buffer, 0, buffer.Length);
while(nRead > 0)
{
output.Write(buffer, 0, nRead );
nTotalBytesWritten += nRead ;
nCount = input.Read(buffer, 0, buffer.Length);
}
}
}
}
}
注意事项:
1. 上传文件的大小还是受IIS限制的,大约超过1G之后,就Stream input = Request.InputStream;就会出现问题。如果要上传超大文件,比如10G以上,这需要客户端对文件进行处理,分块上传,最后服务端接收分块,最后合并,还原。
2. 不要在客户端的HttpEndRequest()调用之前使用Session、Response、Request,在对话期间,这些变量都处于连接状态,任何改变都是无效的(比如:Redirect(NewURL),Session这时候是不工作的)。
首先看客户端:
在这里,需要稍微解释下URL的组成。举个例子:http://myWebServer:8080/Handler/FileUploader.aspx
其中 "myWebServer"为Server Host Name,它用来表示服务器的IP地址。
“8080”是该服务器对http开发的端口号,如不指定的话,默认为80
“/Handler/FileUploader.aspx”就是这个URL的UrlPath了
使用Wininet API同服务器打交道,知道这么多久可以了,下面看怎么编写客户端代码。其实它的步骤是很死的,只要按固定套路使用就可以了。
1. 用 InternetOpen 创建一个表示该次连接的Internet句柄
HINTERNET hInternet = ::InternetOpen(_T("Sample String"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
2. 用 InternetConnect 与指定服务器连接,获得本次连接句柄
// hInternet就是InternetOpen返回的句柄
// szServerHostName就是上面例子URL中的“myWebServer”
// nPort是上例的8080,NULL的话表示默认(80)
HINTERNET hConnection = ::InternetConnect(hInternet, szServerHostName, nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
3. 连接成功后,下面就开始发送请求,告诉服务器,我要上传文件了。
// szUrlPath就是上例中的“/Handler/FileUploader.aspx”,注意,最前面的"/"不能省略的。
// accept是一个LPCTSTR数组,表示该URL接受的文件类型。可以用:
// LPCTSTR accept[] = {
// _T("*/*"),
// NULL
// };
// 表示任何类型
HINTERNET hRequest = ::HttpOpenRequest(hConnection, _T("POST"), szUrlPath, NULL, NULL, accept, 0, INTERNET_FLAG_EXISTING_CONNECT|INTERNET_FLAG_NO_AUTO_REDIRECT|INTERNET_FLAG_HYPERLINK);
INTERNET_BUFFERS ib;
memset(&ib, 0, sizeof(INTERNET_BUFFERS));
ib.dwStructSize = sizeof(INTERNET_BUFFERS);
ib.dwBufferTotal = dwTotalSize; //这里是你要传送数据的总大小,比如一个文件的大小::GetFileSize(hFile, 0)
ib.dwBufferLength = dwBufSize; //分次上传的话,每次上传数据的大小,比如4里面的dwBufSize
::HttpSendRequestEx(hRequest, &ib, 0, HSR_INITIATE, 0));
4. 请求发送成功后,就可以传送数据了,传送数据使用的是::InternetWriteFile这个API
DWORD dwBufSize = 1024*1024; //1M
TCHAR* buffer = new TCHAR[dwBufSize];
DWORD dwRead;
::InternetWriteFile(hRequest, buffer, dwBufSize, &dwRead);
这样就把数据发送到服务端了。
5. 紧接着,客户端需要调用HttpEndRequest()等待服务器处理。这个时候,客户端的执行实际上是停止在这里的,只有当服务段接受完数据,完成处理后,客户端才接着执行下去。
6. 下面就是释放前面申请的句柄和内存了。
以上是客户端向服务器发送数据的全部过程了,如果想传送文件的话,需要在4里面,用一个循环,将文件数据不断读取到buffer里,并用InternetWriteFile发送出去。
服务端:
服务端就负责接收数据了,以下是C# asp.net的样例。
其实,也就是用Request不断从管道里读取上传的数据。
http://myWebServer:8080/Handler/FileUploader.aspx的cs文件
FileUploader.cs文件
public class FileUpload : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Stream input = Request.InputStream;
if (input.Length > 0)
{
String filepath = MapPath("~/Temp/UploadedFile.dat");
using (FileStream output = File.Create(filepath))
{
byte[] buffer = new byte[1024];
int nTotalBytesWritten = 0;
int nRead = input.Read(buffer, 0, buffer.Length);
while(nRead > 0)
{
output.Write(buffer, 0, nRead );
nTotalBytesWritten += nRead ;
nCount = input.Read(buffer, 0, buffer.Length);
}
}
}
}
}
注意事项:
1. 上传文件的大小还是受IIS限制的,大约超过1G之后,就Stream input = Request.InputStream;就会出现问题。如果要上传超大文件,比如10G以上,这需要客户端对文件进行处理,分块上传,最后服务端接收分块,最后合并,还原。
2. 不要在客户端的HttpEndRequest()调用之前使用Session、Response、Request,在对话期间,这些变量都处于连接状态,任何改变都是无效的(比如:Redirect(NewURL),Session这时候是不工作的)。