利用tcp协议实现本机上文件传输

利用tcp协议实现本机上的文件传输,使用c++中fstream对文件进行操作

实现时出现的问题

1. 在接受数据时,文件大小应当根据接收到字符串的实际长度来减少,而不是根据接收时recv返回值来减小

2.在接受数据时,接受循环条件写错,写为(文件大小   == 0 )  ,以及根据接收时recv返回值来减小,导致减为负数造成死循环

3.在vs2022中使用inet_addr()为sin_addr赋值会报错,不安全

sockline.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

所以使用WS2tcpip.h头文件下的InetPtonW()

InetPtonW(AF_INET, L"127.0.0.1", &sockline.sin_addr);

收获

1.在命名时注意名字的意义,一个好名字可以不出错

2.对待问题考虑要全面,不仅仅要知道怎么能改对,还要知道bug产生的原因,bug造成的后果

服务器

#include<iostream>
#include<WinSock2.h>
#include<Windows.h>
#include<fstream>
#pragma comment(lib,"Ws2_32")
using namespace std;

DWORD WINAPI ThreadProc(
    _In_ LPVOID lpParameter
);//线程函数声明


int main()
{
    //创建连接 wsastartup()
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        
        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }

                 
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
       
        printf("Could not find a usable version of Winsock.dll\n");
        WSACleanup();
        return 1;
    }
    else
        printf("The Winsock 2.2 dll was found okay\n");


    //创建套接字
    SOCKET  sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET)
    {
        WSACleanup();
        return 1;
    }


    //绑定地址 bind,这里 sockaddr 使用的是sockaddr_in类型的
    sockaddr_in sockline;
    sockline.sin_family = AF_INET;
    sockline.sin_port = htons(1234);
    sockline.sin_addr.S_un.S_addr = 0;//服务器为本机,可以直接赋值0
    if (SOCKET_ERROR == bind(sock, (const sockaddr*)&sockline, sizeof(sockline)))
    {
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    //监听信息
    if (listen(sock, 10))
    {
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    sockaddr sockll;
    int nsize = sizeof(sockll);
    while (1)
    {
        //为监听到的信息创建套接字
        SOCKET sockwinter = accept(sock, &sockll, &nsize);

        //创建线程
        CreateThread(0, 0, &ThreadProc, (void*)sockwinter, 0, 0);
    }
	

    closesocket(sock);
    WSACleanup();

	return 0;
}





DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter)
{
    SOCKET sockwinter = (SOCKET)lpParameter;
    while (1)
    {
        char wenjianmingjie[1024] = {0};//接受信息的字符串
        int wenjiandaxiao = 0;//文件大小
        char wenjianming[64] = {0};//文件名
        //接受文件名,文件大小
        int nrecv1 = recv(sockwinter, wenjianmingjie, sizeof(wenjianmingjie), 0);
        if (nrecv1 >= 0)//接受到一个字符串前面为名字,后面为大小,中间空格连接
        {
            char* c = wenjianmingjie;
            int i = 0;
            while (*c != ' '&&*c != '\0')
            {
                wenjianming[i++] = *c;
                c++;
            }
            cout << wenjianming << endl;
            c++;
            while (*c != '\0')
            {
                wenjiandaxiao = wenjiandaxiao * 10 + ( * c - '0');
                c++;
            }
        }
        //是否接受,发送信息给客户端
        cout << "是否接受" << endl;
        cout << "yes or no" << endl;
        char querenxinxi[100];
        cin >> querenxinxi;
        send(sockwinter, querenxinxi, sizeof(querenxinxi), 0);


        //进行比较
        if (strcmp(querenxinxi,"yes") == 0)
        {
            char baocunweizhi[1024];//保存位置字符串
            cout << "请输入保存位置" << endl;
            cin >> baocunweizhi;
            ofstream os;
            os.open(baocunweizhi);
            
            while (wenjiandaxiao > 0)//文件大小,每次接收到就减小
            {
                char wenjianhuan[1024] = {0};
                int nrecv2 = recv(sockwinter, wenjianhuan, sizeof(wenjianhuan),0);
                if (nrecv2 >= 0)
                {
                    wenjiandaxiao -= (int)strlen(wenjianhuan);//减去实际接受到的信息大小
                    os << wenjianhuan;//写入文件
                }
            }
            os.close();//关闭文件

        }





    }

}

客户端


#include<iostream>
#include<WinSock2.h>
#include<Windows.h>
#include<fstream>
#include<WS2tcpip.h>

#pragma comment(lib,"Ws2_32")

using namespace std;

int main()
{

    //建立连接
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {

        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }


    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {

        printf("Could not find a usable version of Winsock.dll\n");
        WSACleanup();
        return 1;
    }
    else
        printf("The Winsock 2.2 dll was found okay\n");


    //创建套接字
    SOCKET  sock = socket(AF_INET, SOCK_STREAM, 0);

    
    sockaddr_in sockline;
    sockline.sin_family = AF_INET;
    sockline.sin_port = htons(1234);
    InetPtonW(AF_INET, L"127.0.0.1", &sockline.sin_addr);
    if (SOCKET_ERROR == connect(sock, (const sockaddr*)&sockline, sizeof(sockline)))
    {
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    //打开文件
    ifstream is;
    char wenjiandizhi[1024];
    cout << "请输入文件地址" << endl;
    cin >> wenjiandizhi;
    
    //解析出文件名
    char wenjianming[62] = {0};
    char* c = wenjiandizhi;

    while (*c != '\0')
    {
        c++;
    }

    while (*c != '\\')
    {
        c--;
    }
    c++;
    strcpy_s(wenjianming, c);

    //读取文件大小
    unsigned int wenjiandaxiao = 0;
    char wenjian[1024];
    is.open(wenjiandizhi);
    while (is >> wenjian)
    {
        wenjiandaxiao += strlen(wenjian);
    }

    is.close();

    //将文件名和文件大小串联在一起,中间用空格连接
    char s[1024];
    sprintf_s(s, "%d", wenjiandaxiao);
    strcat_s(wenjianming," ");
    strcat_s(wenjianming,s);


    //发送文件名字与大小
    send(sock, wenjianming, sizeof(wenjianming), 0);


    //接受确认信息
    char querenxinxi[100];
    int recvn = recv(sock, querenxinxi, sizeof(querenxinxi), 0);
    if (recvn >= 0)
    {
        if (strcmp(querenxinxi,"yes") == 0)
        {
            //发送文件
            is.open(wenjiandizhi);
           while( is >> wenjian)
            send(sock, wenjian, sizeof(wenjian), 0);
           is.close();
        }
    }

    closesocket(sock);

    WSACleanup();


	return 0;
}

存在问题

在上面通信中使用的是多线程实现一个服务器与多线程通信,在创建线程和套接字时没有保存下来句柄和套接字,应使用数组记录下来,在使用结束时关闭线程和套接字

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值