这个实现了客户端和服务端文件的相互传输(只在本机上运行过),如果是要两台计算机相互传数据要改ip
给大家看一下实现过程(.exe文件要先开服务端的)
输入1
直接将快捷方式拖拽上去就有绝对路径了,然后回车
用的是分组传输
然后服务端就接受到传输的文件了 ,从服务端取文件的过程是一样的。
上代码
客户端的头文件
ftpclient.h
#pragma once
#include
#pragma comment(lib,"ws2_32.lib") // 加载静态库
#include
#define SPORT 8888 // 服务器端口号
#define PACKET_SIZE (1024 - sizeof(int) * 3)
// 定义标记
enum MSGTAG
{
MSG_FILENAME = 1, // 文件名称 服务器使用
MSG_FILESIZE = 2, // 文件大小 客户端使用
MSG_READY_READ = 3, // 准备接受 客户端使用
MSG_SENDFILE = 4, // 发送 服务器使用
MSG_SUCCESSED = 5, // 传输完成 两者都使用
MSG_OPENFILE_FAILD = 6, // 告诉客户端文件找不到 客户端使用
MSG_CLIENTREADSENT = 7, //客户端发送路径和文件大小
MSG_SERVERREAD = 8, //服务端申请空间
MSG_CLIENTSENT = 9 //客户端传输
};
#pragma pack(1) // 设置结构体1字节对齐**************
struct MsgHeader // 封装消息头
{
enum MSGTAG msgID; // 当前消息标记 4
union MyUnion
{
struct Mystruct
{
int fileSize; // 文件大小 4
char fileName[256]; // 文件名 256
}fileInfo;
struct
{
int nStart; // 包的编号
int nsize; // 该包的数据大小
char buf[PACKET_SIZE];
}packet;
};
};
#pragma pack()
// 初始化socket库
bool initSocket();
// 关闭socket库
bool closeSocket();
// 监听客户端连接
void connectToHost();
// 处理消息
bool processMag(SOCKET serfd);
// 获取文件名
void downloadFileName(SOCKET serfd);
// 文件内容读进内存
void readyread(SOCKET, struct MsgHeader*);
// 写入文件内容
bool writeFile(SOCKET, struct MsgHeader*);
//服务端发送文件路径和大小 然后在自己的缓冲区将文件缓存下来
void clientReadySend(SOCKET);
//准备开始发送文件
bool sendFile(SOCKET, struct MsgHeader*);
客户端.c文件
ftpclient.c
#include
#include
#include "ftpclient.h"
char g_fileName[256]; // 保存服务器发送过来的文件名
char* g_fileBuf; // 接受存储文件内容
char g_recvBuf[1024]; // 接受消息缓冲区
int g_fileSize; // 文件总大小
int main(void)
{
initSocket();
connectToHost();
closeSocket();
return 0;
}
// 初始化socket库
bool initSocket()
{
WSADATA wsadata;
if (0 != WSAStartup(MAKEWORD(2, 2), &wsadata)) // 启动协议,成功返回0
{
printf("WSAStartup faild: %d\n", WSAGetLastError());
return false;
}
return true;
}
// 关闭socket库
bool closeSocket()
{
if (0 != WSACleanup())
{
printf("WSACleanup faild: %d\n", WSAGetLastError());
return false;
}
return true;
}
// 监听客户端连接
void connectToHost()
{
// 创建server socket套接字 地址、端口号,AF_INET是IPV4
SOCKET serfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == serfd)
{
printf("socket faild:%d", WSAGetLastError());
return;
}
// 给socket绑定IP地址和端口号
struct sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(SPORT); // htons把本地字节序转为网络字节序
serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 服务器的IP地址
// 连接到服务器
if (0 != connect(serfd, (struct sockaddr*)&serAddr, sizeof(serAddr)))
{
printf("connect faild:%d", WSAGetLastError());
return;
}
printf("连接成功!\n");
while (1)
{
int flag;
printf("请你选择是要接受文件还是选择结束\n");
printf("***************************************\n");
printf("1.传输文件给服务端\n");
printf("2.从服务端取文件\n");
printf("3.退出程序\n");
printf("***************************************\n");
do {
scanf_s("%d", &flag);
} while (!(flag == 1 || flag == 2 || flag == 3));
system("cls");
if (flag == 1)
{
printf("现在开始向服务端传输文件");
clientReadySend(serfd);
while(processMag(serfd))
{}
}
else if(flag == 2)
{
printf("现在客户端开始接收文件\n");
downloadFileName(serfd);// 开始处理消息,100为发送消息间隔
while (processMag(serfd))
{}
}
else
{
printf("系统要退出了...\n");
closesocket(serfd);
return false;
}
printf("\nPress Any Key To Continue:");
_getch();
system("cls");
}
}
// 处理消息
bool processMag(SOCKET serfd)
{
recv(serfd, g_recvBuf, 1024, 0); // 收到消息
struct MsgHeader* msg = (struct MsgHeader*)g_recvBuf;
/*
*MSG_FILENAME = 1, // 文件名称 服务器使用
*MSG_FILESIZE = 2, // 文件大小 客户端使用
*MSG_READY_READ = 3, // 准备接受 客户端使用
*MSG_SENDFILE = 4, // 发送 服务器使用
*MSG_SUCCESSED = 5, // 传输完成 两者都使用
*MSG_OPENFILE_FAILD = 6 // 告诉客户端文件找不到 客户端使用
*/
switch (msg->msgID)
{
case MSG_OPENFILE_FAILD: // 6
downloadFileName(serfd);
break;
case MSG_FILESIZE: // 2 第一次接收
readyread(serfd, msg);
break;
case MSG_READY_READ: // 3
writeFile(serfd, msg);
break;
case MSG_SUCCESSED: // 5
printf("传输完成!\n");
return false;
brea