利用流式套接字实现文件传输.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