利用流式套接字实现文件传输.md
来源:互联网 发布:阿里妈妈淘宝客收费吗 编辑:程序博客网 时间:2024/05/16 16:19
流式套接字实现简单的客户端/服务端通信过程
一、 实验内容
- 客户端向服务端发起socket连接,并建立数据传输通道;
- 客户端向服务端发送要传输的文件名称,以‘#’字符结 尾,服务端逐字符接收,直到接收到#;(变长数据)
- 客户端向服务端发送文件长度,4字节;(定长数据)
- 客户端向服务端发送文件内容;(变长数据)
- 服务端接收完文件后,向客户端发送‚OK‛,以示成功接 收。
- 客户端接收到‚OK‛后,关闭套接字。
- 服务端关闭套接字。
二、 实验要求
提交源码(源码编写要规范)、可执行程序、实验报告(要有程序运行截图)。
三、 实验分析
server:
接收文件名
if( !(fp = fopen(file_name, "wb")) ) { cout<<"File "<<file_name<<" can't open"<<endl; closesocket(ClientSocket); return -1; } reclen = file_len; while( reclen > 0 ) { //如果recvbuf没有足够的空间存储变长消息,则接收该消息并丢弃,返回错误 if( reclen > BUFFER_LEN ) { iResult = recvn( ClientSocket, RecvBuffer, BUFFER_LEN); if( iResult != BUFFER_LEN ) { //如果变长消息在接收时没有返回足够的数据就返回(连接关闭)或-1(发生错误) if( iResult == -1 ) { cout<<"Received Error:"<<WSAGetLastError()<<endl; return -1; } else { cout<<"Connection Closed!"<<endl; closesocket(ClientSocket); return 0; } } recvbuflen = fwrite(RecvBuffer, sizeof(char), BUFFER_LEN, fp); fflush(fp);//强制写入 if( recvbuflen != BUFFER_LEN ) { cout<<"Receive File Length Error!"<<endl; closesocket(ClientSocket); //关闭客户端的socket连接 return -1; } memset(RecvBuffer, 0, BUFFER_LEN); reclen -= BUFFER_LEN; } else { iResult = recvn(ClientSocket, RecvBuffer, reclen); if( iResult != reclen ) { if( iResult == -1) { cout<<"Received Error!"<<endl; closesocket(ClientSocket); //关闭客户端的socket连接 return -1; } else { cout<<"Client:"<<ClientIp<<":"<<ClientPort<<" Closed!"<<endl; closesocket(ClientSocket); //关闭客户端的socket连接 return 0; } } recvbuflen = fwrite(RecvBuffer, sizeof(char), reclen, fp); fflush(fp); if( recvbuflen != reclen ) { cout<<"Receive Length Error!"<<endl; closesocket(ClientSocket); //关闭客户端的socket连接 return -1; } memset(RecvBuffer, 0, BUFFER_LEN); reclen = 0; } } fclose(fp);
返回OK
cout<<"Receive "<<ClientIp<<":"<<ClientPort<<" file:"<<file_name<<" Successful!"<<endl; strncpy(RecvBuffer,"OK",2); iResult = send(ClientSocket, RecvBuffer , 2, 0); //若接收到了,则会直接回送给客户端 if ( iResult == 0 || iResult == SOCKET_ERROR ) { cout<<"Client "<<ClientIp<<":"<<ClientPort<<" Exit!"<<endl; closesocket(ClientSocket); return -1; }
client
发送文件名
cout<<"Please send File name first:"<<endl;cin>>file_name;memset(SendBuffer, 0x00, BUFFER_LEN);// cin.getline(SendBuffer, sizeof(SendBuffer),'#');strncpy(SendBuffer, file_name, strlen(file_name));SendBuffer[strlen(file_name)]='#'; //设置文件名结束标志
发送文件长度
if( !(fp = fopen(file_name,"rb")) ){ cout<<"File "<<file_name<<" can't open"<<endl; continue;}fseek(fp,0,SEEK_END);iResult = send(ClientSocket, SendBuffer, strlen(file_name)+1, 0);memset(SendBuffer, 0x00, BUFFER_LEN);file_size = (unsigned int)ftell(fp);// longBytes就是文件的长度//cout<<file_size<<endl;file_size = htonl(file_size);iResult = send(ClientSocket, (char*)&file_size, 4, 0);
发送文件内容
while (len > 0){ iResult = send(ClientSocket, SendBuffer, len, 0); memset(SendBuffer, 0, BUFFER_LEN); len = fread(SendBuffer, sizeof(char ), BUFFER_LEN,fp); if(iResult == SOCKET_ERROR) { cout<<"Send File Error::"<<GetLastError()<<endl; closesocket(ClientSocket); //关闭socket WSACleanup(); return -1; } else if(iResult == 0) { cout<<"Send File failure!"<<endl; continue; } }
截图:
错误处理
第一次版本的时候,出现的错误:当文件长度超过了一定值之后,Client就会因此崩溃,逻辑上应该再次分块重传,不知道细节就停在这儿了
错误的原因其实也很简单:Server在收的时候,每次接收的长度需要累加,不然缓冲区一直接收会爆炸,也不可能存得下大文件。
心得
边学边复制边改错边调整,学到很多东西。很多细节只有自己犯错之后才知道如何调整,也很喜欢这种学习方式,很有成就感。需要付出更多,代码量到了一定程度之后,才会有更多的经验和更强的能力
源码:
server
#include <iostream>#include <cstdio>#include <stdlib.h>#include <winsock2.h>using namespace std;#pragma comment(lib, "ws2_32.lib")#define PORT 4000#define IP_ADDRESS "127.0.0.1"#define BUFFER_LEN 1000#define MAX_NAME 32//char ClientIp[20];//unsigned short int ClientPort;int recvn( SOCKET s ,char * RecvBuffer,unsigned int fixedlen){ int iResult; //存储单次recv操作的返回值 int cnt; //用于统计相对于固定长度,剩余多少字节尚未接收 cnt = fixedlen; while( cnt > 0) { iResult = recv(s,RecvBuffer,cnt,0); if( iResult < 0) { //数据接收出现错误,返回失败 cout<<"Received error: "<<WSAGetLastError()<<endl; closesocket(s); return -1; } if( iResult == 0) { //对方关闭连接,返回已接收到的小于fixedlen的字节数 cout<<"Connection closed"<<endl; closesocket(s); return fixedlen - cnt; } //cout<<"接受到的字节数:"<<iResult<<endl; //接收缓存指针向后移动 RecvBuffer += iResult; //更新cnt值 cnt -= iResult; } return fixedlen;}DWORD WINAPI ClientThread(LPVOID lpParameter){ SOCKET ClientSocket = (SOCKET)lpParameter; int iResult = 0; char RecvBuffer[BUFFER_LEN]; char file_name[MAX_NAME]; int file_len; FILE *fp; struct sockaddr_in ClientAddr; int ClientAddrlen = sizeof(SOCKADDR_IN); char ClientIp[20]; unsigned int ClientPort; unsigned int reclen = 0; unsigned int recvbuflen; getpeername(ClientSocket,(SOCKADDR *)&ClientAddr, &ClientAddrlen); strcpy(ClientIp, inet_ntoa(ClientAddr.sin_addr)); ClientPort = ntohs(ClientAddr.sin_port); cout<<"Client:"<<ClientIp<<":"<<ClientPort<<" Connection!"<<endl; while ( true ) { memset(RecvBuffer, 0, sizeof(RecvBuffer)); int i=0; for(i = 0; file_name[i-1] != '#'; i++) { while(!(iResult = recv(ClientSocket, RecvBuffer, 1, 0))); //cout<<file_name; file_name[i] = RecvBuffer[0]; memset(RecvBuffer, 0, sizeof(RecvBuffer)); } file_name[i-1] = '\0'; // reclen = ntohl( reclen ); iResult = recvn(ClientSocket,(char*)&file_len, 4); file_len = ntohl(file_len); if( iResult != 4 ) { //如果消息在接收时没有返回足够的数据就返回(连接关闭)或-1(发生错误) if( iResult == -1) { cout<<"Received Error:"<<WSAGetLastError()<<endl; closesocket(ClientSocket); //关闭客户端的socket连接 return -1; } else { cout<<"Connection Closed!"<<endl; closesocket(ClientSocket); return 0; } } if( !(fp = fopen(file_name, "wb")) ) { cout<<"File "<<file_name<<" can't open"<<endl; closesocket(ClientSocket); return -1; } reclen = file_len; while( reclen > 0 ) { //如果recvbuf没有足够的空间存储变长消息,则接收该消息并丢弃,返回错误 if( reclen > BUFFER_LEN ) { iResult = recvn( ClientSocket, RecvBuffer, BUFFER_LEN); if( iResult != BUFFER_LEN ) { //如果变长消息在接收时没有返回足够的数据就返回(连接关闭)或-1(发生错误) if( iResult == -1 ) { cout<<"Received Error:"<<WSAGetLastError()<<endl; return -1; } else { cout<<"Connection Closed!"<<endl; closesocket(ClientSocket); return 0; } } recvbuflen = fwrite(RecvBuffer, sizeof(char), BUFFER_LEN, fp); fflush(fp);//强制写入 if( recvbuflen != BUFFER_LEN ) { cout<<"Receive File Length Error!"<<endl; closesocket(ClientSocket); //关闭客户端的socket连接 return -1; } memset(RecvBuffer, 0, BUFFER_LEN); reclen -= BUFFER_LEN; } else { iResult = recvn(ClientSocket, RecvBuffer, reclen); if( iResult != reclen ) { if( iResult == -1) { cout<<"Received Error!"<<endl; closesocket(ClientSocket); //关闭客户端的socket连接 return -1; } else { cout<<"Client:"<<ClientIp<<":"<<ClientPort<<" Closed!"<<endl; closesocket(ClientSocket); //关闭客户端的socket连接 return 0; } } recvbuflen = fwrite(RecvBuffer, sizeof(char), reclen, fp); fflush(fp); if( recvbuflen != reclen ) { cout<<"Receive Length Error!"<<endl; closesocket(ClientSocket); //关闭客户端的socket连接 return -1; } memset(RecvBuffer, 0, BUFFER_LEN); // cout<<"1"<<endl; reclen = 0; } } fclose(fp); if( reclen == 0) { cout<<"Receive "<<ClientIp<<":"<<ClientPort<<" file:"<<file_name<<" Successful!"<<endl; strncpy(RecvBuffer,"OK",2); iResult = send(ClientSocket, RecvBuffer , 2, 0); //若接收到了,则会直接回送给客户端 if ( iResult == 0 || iResult == SOCKET_ERROR ) { cout<<"Client "<<ClientIp<<":"<<ClientPort<<" Exit!"<<endl; closesocket(ClientSocket); return -1; } } else { cout<<"Receive "<<ClientIp<<":"<<ClientPort<<" File:"<<file_name<<" Failed!"<<endl; strncpy(RecvBuffer,"NO",2); iResult = send(ClientSocket, RecvBuffer , 2, 0); //若接收到了,则会直接回送给客户端 if (iResult == 0 || iResult == SOCKET_ERROR) //如果回送失败,则提示并退出 { cout<<"Send Info Error:"<<GetLastError()<<endl; closesocket(ClientSocket); //关闭客户端的socket连接 return -1; } closesocket(ClientSocket); //关闭客户端的socket连接 } } cout<<"Client:"<<ClientIp<<":"<<ClientPort<<" Exit!"<<endl; return 0;}int main(int argc, char* argv[]){ WSADATA Ws; SOCKET ServerSocket, ClientSocket; struct sockaddr_in LocalAddr, ClientAddr; int iResult = 0; int AddrLen = 0; HANDLE hThread = NULL; //Init Windows Socket if ( WSAStartup(MAKEWORD(2, 2), &Ws) != 0 ) { cout<<"Init Windows Socket Failed:"<<GetLastError()<<endl; closesocket(ClientSocket); return -1; } //Create Socket ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if ( ServerSocket == INVALID_SOCKET ) { cout<<"Create Socket Failed:"<<GetLastError()<<endl; closesocket(ServerSocket); WSACleanup(); return -1; } LocalAddr.sin_family = AF_INET; LocalAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS); LocalAddr.sin_port = htons(PORT); memset(LocalAddr.sin_zero, 0x00, 8); //Bind Socket iResult = bind(ServerSocket, (struct sockaddr*)&LocalAddr, sizeof(LocalAddr)); if ( iResult != 0 ) { cout<<"Bind Socket Failed::"<<GetLastError()<<endl; closesocket(ServerSocket); WSACleanup(); return -1; } //listen iResult = listen(ServerSocket, 10); if ( iResult != 0 ) { cout<<"listen Socket Failed::"<<GetLastError()<<endl; closesocket(ClientSocket); return -1; } cout<<"Server is started!"<<endl; while ( true ) { AddrLen = sizeof(ClientAddr); ClientSocket = accept(ServerSocket, (struct sockaddr*)&ClientAddr, &AddrLen); if ( ClientSocket == INVALID_SOCKET ) { cout<<"Accept Failed:"<<GetLastError()<<endl; closesocket(ClientSocket); break; } cout<<"Client Connected:"<<inet_ntoa(ClientAddr.sin_addr)<<":"<<ntohs(ClientAddr.sin_port)<<endl; hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)ClientSocket, 0, NULL); if ( hThread == NULL ) { cout<<"Create Thread Failed!"<<endl; closesocket(ClientSocket); break; } CloseHandle(hThread); } closesocket(ServerSocket); //closesocket(ClientSocket); WSACleanup(); return 0;}
client
#include <iostream>#include <stdio.h>#include <winsock2.h>using namespace std;#pragma comment(lib, "ws2_32.lib")//#define PORT 4000//#define IP_ADDRESS "127.0.0.1"#define BUFFER_LEN 1000int main(int argc, char * argv[]){ WSADATA Ws; SOCKET ClientSocket; struct sockaddr_in ServerAddr; int iResult = 0; HANDLE hThread = NULL; char SendBuffer[BUFFER_LEN]; char RecvBuffer[BUFFER_LEN]; char IP_ADDRESS[15]; unsigned short int PORT; char file_name[MAX_PATH]; FILE *fp; unsigned int file_size; //Init Windows Socket if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 ) { cout<<"Init Windows Socket Failed::"<<GetLastError()<<endl; WSACleanup(); return -1; } //Create Socket ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if ( ClientSocket == INVALID_SOCKET ) { cout<<"Create Socket Failed:"<<GetLastError()<<endl; closesocket(ClientSocket); WSACleanup(); return -1; } cout<<"Input Server IP:"<<endl; cin>>IP_ADDRESS; cout<<"Input Server PORT:"<<endl; cin>>PORT; ServerAddr.sin_family = AF_INET; ServerAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS); ServerAddr.sin_port = htons(PORT); memset(ServerAddr.sin_zero, 0x00, 8); iResult = connect(ClientSocket, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr)); if ( iResult == SOCKET_ERROR ) { cout<<"Connect Error:"<<GetLastError()<<endl; closesocket(ClientSocket); WSACleanup(); return -1; } else { cout<<"Connect Success!"<<endl; cout<<"Server Address:"<<inet_ntoa(ServerAddr.sin_addr)<<"::"<<ntohs(ServerAddr.sin_port)<<endl; //连接成功,显示服务器的IP和端口信息 } while ( true ) { cout<<"Please send File name first:"<<endl; cin>>file_name; memset(SendBuffer, 0x00, BUFFER_LEN); strncpy(SendBuffer, file_name, strlen(file_name)); SendBuffer[strlen(file_name)]='#'; //设置文件名结束标志 if( !(fp = fopen(file_name,"rb")) ) { cout<<"File "<<file_name<<" can't open"<<endl; continue; } fseek(fp,0,SEEK_END); iResult = send(ClientSocket, SendBuffer, strlen(file_name)+1, 0); memset(SendBuffer, 0x00, BUFFER_LEN); file_size = (unsigned int)ftell(fp);// longBytes就是文件的长度 //cout<<file_size<<endl; file_size = htonl(file_size); iResult = send(ClientSocket, (char*)&file_size, 4, 0); if ( iResult == SOCKET_ERROR ) { cout<<"Send File Error::"<<GetLastError()<<endl; return -1; } else if (iResult == 0) { cout<<"Send File name failure!"<<endl; continue; } rewind(fp); memset(SendBuffer, 0, BUFFER_LEN); int len = fread(SendBuffer, sizeof(char ), BUFFER_LEN,fp); while (len > 0) { iResult = send(ClientSocket, SendBuffer, len, 0); memset(SendBuffer, 0, BUFFER_LEN); len = fread(SendBuffer, sizeof(char ), BUFFER_LEN,fp); if(iResult == SOCKET_ERROR) { cout<<"Send File Error::"<<GetLastError()<<endl; closesocket(ClientSocket); //关闭socket WSACleanup(); return -1; } else if(iResult == 0) { cout<<"Send File failure!"<<endl; continue; } } memset(SendBuffer, 0, BUFFER_LEN); fclose(fp); cout<<"File "<<file_name<<" Send Successful!"<<endl; memset(RecvBuffer, 0, BUFFER_LEN); iResult = recv(ClientSocket, RecvBuffer, 2, 0); cout<<RecvBuffer<<endl; if(iResult == 0 || iResult == SOCKET_ERROR) { cout<<"Received Error!"<<endl; closesocket(ClientSocket); //关闭socket WSACleanup(); //释放DLL return -1; } if(!strncmp(RecvBuffer,"OK",2)) { cout<<"Transfer File Success!"<<endl; closesocket(ClientSocket); //关闭socket WSACleanup(); //释放DLL return -1; } else //if(strncmp(RecvBuffer,"OK",2)) { cout<<"Transfer File Failed!"<<endl; closesocket(ClientSocket); //关闭socket WSACleanup(); //释放DLL return -1; } // iResult = recv(ClientSocket, RecvBuffer, BUFFER_LEN, 0);//接收到服务器的回显 } closesocket(ClientSocket); WSACleanup(); return 0;}
0 0
- 利用流式套接字实现文件传输.md
- 利用流式套接字实现文件传输
- 【网络编程】利用流式套接字实现文件传输实验
- 基于流式套接字实现文件传输
- 利用数据报套接字实现数据传输及文件传输
- 套接字文件传输
- NET System.Sockes类套接字,实现点对点文件传输
- 利用流式套接字传输数据文件
- 利用remoting实现文件传输
- 利用Android实现文件传输
- 利用Unix域套接字实现IPC
- 利用.net Remoting 实现文件传输
- 使用Java的Socket套接字实现echo和大文件传输
- 利用套接字实现UDP 通信 小测
- 利用原始套接字实现tracert路由追踪
- 关于利用Tcp库来实现文件传输
- 利用axis创建webservice实现文件传输
- Android利用WifiDirect实现文件传输功能
- 基于Basys 3的四位加法运算器
- 欢迎使用CSDN-markdown编辑器
- Laravel的json响应
- [译]c++ web编程:写出你的CGI程序
- JavaScript数据机构——集合
- 利用流式套接字实现文件传输.md
- 深入理解java接口和抽象类
- 【工具】markdown字体或者图片居中
- HLS byterange
- leetcode note--leetcode 345 Reverse Vowels of a String
- TP框架连接数据库
- 【模式识别与机器学习(PRML)读书笔记】1.绪论
- RecyclerView完全解析
- Struts2框架搭建与简单的登陆实例