FTP综合应用编程(C++)

1.学校实验的最后一个。。。

     借鉴了网上以为大佬的作品,然后自己改改拿来完成了算是还行的作品。

     代码一共大概是900多行,可以直接粘贴下来看看,其实还是很容易理解的。

     运行的截图附上:

     客户端:

服务器端:

2.服务器端代码

头文件:(sizes.h)

#pragma once

//服务器侦听控制连接请求的端口
#define CMD_PORT 5858
//客户机侦听数据连接请求的端口
#define DATA_PORT 5850
//命令报文参数缓存的大小
#define CMD_PARAM_SIZE 256
//回复报文消息缓存的大小
#define RSPNS_TEXT_SIZE 256
#define BACKLOG 10
#define DATA_BUFSIZE 4096

//命令类型
typedef enum {
	LS, PWD, CD, DOWN, UP, QUIT
} CmdID;

//命令报文,从客户端发往服务器
typedef struct _CmdPacket {
	CmdID cmdid;
	char param[CMD_PARAM_SIZE];
} CmdPacket;

//回复报文的类型
typedef enum {
	OK, ERR
} RspnsID;

//回复报文,从服务器发往客户端
typedef struct _RspnsPacket {
	RspnsID rspnsid;
	char text[RSPNS_TEXT_SIZE];
} RspnsPacket;

源文件:(服务器端.cpp)

#include <WinSock2.h>
#include "sizes.h"
#include <iostream>

#pragma comment(lib, "ws2_32.lib")

//创建线程时传递的数据结构,内含控制连接套接字和客户端地址信息:
struct threadData {
	SOCKET tcps;
	sockaddr_in clientaddr;
};

//全局函数声明:
//FTP初始化,创建一个侦听套接字:
int InitFTP(SOCKET *pListenSock);
int InitDataSocket(SOCKET *pDatatcps, SOCKADDR_IN *pClientAddr);
int ProcessCmd(SOCKET tcps, CmdPacket* pCmd, SOCKADDR_IN *pClientAddr);
int SendRspns(SOCKET tcps, RspnsPacket* prspns);
int RecvCmd(SOCKET tcps, char* pCmd);
int SendFileList(SOCKET datatcps);
int SendFileRecord(SOCKET datatcps, WIN32_FIND_DATA* pfd);
int SendFile(SOCKET datatcps, FILE* file);
int RecvFile(SOCKET datatcps, char* filename);
int FileExists(const char *filename);

//线程函数,参数包括相应控制连接的套接字:
DWORD WINAPI ThreadFunc(LPVOID lpParam) {
	SOCKET tcps;
	sockaddr_in clientaddr;
	tcps = ((struct threadData *)lpParam)->tcps;
	clientaddr = ((struct threadData *)lpParam)->clientaddr;
	printf("socket的编号是:%u.\n", tcps);

	//发送回复报文给客户端,内含命令使用说明:
	printf("Serve client %s:%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
	RspnsPacket rspns = { OK,
			"欢迎进入FTP综合应用系统!\n"
			"你可以使用的命令:\n"
			"ls\t<展示当前目录下的文件(夹),无需参数>\n"
			"pwd\t<展示当前目录的绝对路径,无需参数>\n"
			"cd\t<切换到指定目录,参数为路径>\n"
			"down\t<下载文件,参数为文件名>\n"
			"up\t<上传文件,参数为文件名>\n"
			"quit\t<退出系统,无需参数>\n"
	};
	SendRspns(tcps, &rspns);

	//循环获取客户端命令报文并进行处理
	for (;;) {
		CmdPacket cmd;
		if (!RecvCmd(tcps, (char *)&cmd))
			break;
		if (!ProcessCmd(tcps, &cmd, &clientaddr))
			break;
	}

	//线程结束前关闭控制连接套接字:
	closesocket(tcps);
	delete lpParam;
	return 0;
}

int main(int argc, char* argv[]) {
	SOCKET tcps_listen;  //FTP服务器控制连接侦听套接字
	struct threadData *pThInfo;

	if (!InitFTP(&tcps_listen))  //FTP初始化
		return 0;
	printf("FTP服务器开始监听,端口号为:%d。。。。。。\n", CMD_PORT);

	//循环接受客户端连接请求,并生成线程去处理:
	for (;;) {
		pThInfo = NULL;
		pThInfo = new threadData;
		if (pThInfo == NULL) {
			printf("为新线程申请空间失败。\n");
			continue;
		}

		int len = sizeof(struct threadData);
		//等待接受客户端控制连接请求
		pThInfo->tcps = accept(tcps_listen, (SOCKADDR*)&pThInfo->clientaddr, &len);

		//创建一个线程来处理相应客户端的请求:
		DWORD dwThreadId, dwThrdParam = 1;
		HANDLE hThread;

		hThread = CreateThread(
			NULL,               //无需安全性的继承
			0,					//默认线程栈大小
			ThreadFunc,			//线程入口函数
			pThInfo,			//线程入口函数的参数
			0,					//立即启动线程
			&dwThreadId);		//返回线程的id值

		//检查返回值是否创建线程成功
		if (hThread == NULL) {
			printf("创建线程失败。\n");
			closesocket(pThInfo->tcps);
			delete pThInfo;
		}
	}

	return 0;

}

//FTP初始化,创建一个侦听套接字:

int InitFTP(SOCKET *pListenSock) {
	//按照此步骤创建新的服务器端套接字,嗯,没错,前三个都是这个步骤
	//startup->socket->bind->listen
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	SOCKET tcps_listen;

	wVersionRequested = MAKEWORD(2, 2);
	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) {
		printf("Winsock初始化时发生错误!\n");
		return 0;
	}
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		WSACleanup();
		printf("无效Winsock版本!\n");
		return 0;
	}

	tcps_listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (tcps_listen == INVALID_SOCKET) {
		WSACleanup();
		printf("创建Socket失败!\n");
		return 0;
	}

	SOCKADDR_IN tcpaddr;
	tcpaddr.sin_family = AF_INET;
	tcpaddr.sin_port = htons(CMD_PORT);
	tcpaddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	err = bind(tcps_listen, (SOCKADDR*)&tcpaddr, sizeof(tcpaddr));
	if (err != 0) {
		err = WSAGetLastError();
		WSACleanup();
		printf("Scoket绑定时发生错误!\n");
		return 0;
	}
	err = listen(tcps_listen, 3);
	if (err != 0) {
		WSACleanup();
		printf("Scoket监听时发生错误!\n");
		return 0;
	}

	*pListenSock = tcps_listen;
	return 1;
}


//建立数据连接
//pDatatcps:用于存储数据连接套接字
//pClientAddr:指向客户端的控制连接套接字地址,需要使用其中的IP地址
//返回值:0表示失败,1正常
int InitDataSocket(SOCKET *pDatatcps, SOCKADDR_IN *pClientAddr) {
	SOCKET datatcps;

	//创建socket
	datatcps = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (datatcps == INVALID_SOCKET) {
		printf("Creating data socket failed!\n");
		return 0;
	}

	SOCKADDR_IN tcpaddr;
	memcpy(&tcpaddr, pClientAddr, sizeof(SOCKADDR_IN));
	tcpaddr.sin_port = htons(DATA_PORT);    //如若有什么意外只需要在头文件修改端口值

	//请求连接客户端
	if (connect(datatcps, (SOCKADDR*)&tcpaddr, sizeof(tcpaddr)) == SOCKET_ERROR) {
		printf("Connecting to client failed!\n");
		closesocket(datatcps);
		return 0;
	}

	*pDatatcps = datatcps;
	return 1;
}

//处理命令报文
//tcps:控制连接套接字
//pcmd:指向待处理的命令报文
//pClientAddr:指向客户端控制连接套接字地址
//返回值:0表示有错或者需要结束连接,1正常

int ProcessCmd(SOCKET tcps, CmdPacket* pCmd, SOCKADDR_IN *pClientAddr) {
	SOCKET datatcps;   //数据连接套接字
	RspnsPacket rspns;  //回复报文
	FILE* file;

	//根据命令类型分派执行:
	switch (pCmd->cmdid) {
	case LS://展示当前目录下的文件列表
		//首先建立数据连接:
		if (!InitDataSocket(&datatcps, pClientAddr))
			return 0;
		//发送文件列表信息:
		if (!SendFileList(datatcps))
			return 0;
		break;
	case PWD://展示当前目录的绝对路径
		rspns.rspnsid = OK;
		//获取当前目录,并放至回复报文中
		if (!GetCurrentDirectory(RSPNS_TEXT_SIZE, rspns.text))
			strcpy(rspns.text, "Can't get current dir!\n");
		if (!SendRspns(tcps, &rspns))
			return 0;
		break;
	case CD://设置当前目录,使用win32 API 接口函数
		if (SetCurrentDirectory(pCmd->param)) {
			rspns.rspnsid = OK;
			if (!GetCurrentDirectory(RSPNS_TEXT_SIZE, rspns.text))
				strcpy(rspns.text, "切换当前目录成功!但是不能获取到当前的文件列表!\n");
		}
		else {
			strcpy(rspns.text, "不能更换到所选目录!\n");
		}
		if (!SendRspns(tcps, &rspns))   //发送回复报文
			return 0;
		break;
	case DOWN://处理下载文件请求:
		file = fopen(pCmd->param, "rb");   //打开要下载的文件
		if (file) {
			rspns.rspnsid = OK;
			sprintf(rspns.text, "下载文件%s\n", pCmd->param);
			if (!SendRspns(tcps, &rspns)) {
				fclose(file);
				return 0;
			}
			else {
				//创建额外的数据连接来传送数据:
				if (!InitDataSocket(&datatcps, pClientAddr)) {
					fclose(file);
					return 0;
				}
				if (!SendFile(datatcps, file))
					return 0;
				fclose(file);
			}
		}
		else  //打开文件失败
		{
			rspns.rspnsid = ERR;
			strcpy(rspns.text, "不能打开文件!\n");
			if (!SendRspns(tcps, &rspns))
				return 0;
		}
		break;
	case UP://处理上传文件请求
		//首先发送回复报文
		char filename[64];
		strcpy(filename, pCmd->param);
		//首先看一下服务器上是否已经有这个文件里,如果有就告诉客户端不用传输了
		if (FileExists(filename)) {
			rspns.rspnsid = ERR;
			sprintf(rspns.text, "服务器已经存在名字为%s的文件!\n", filename);
			if (!SendRspns(tcps, &rspns))
				return 0;
		}
		else {
			rspns.rspnsid = OK;
			if (!SendRspns(tcps, &rspns))
				return 0;
			//另建立一个数据连接来接受数据:
			if (!InitDataSocket(&datatcps, pClientAddr))
				return 0;
			if (!RecvFile(datatcps, filename))
				return 0;
		}
		break;
	case QUIT:
		printf("客户端断开连接。\n");
		rspns.rspnsid = OK;
		strcpy(rspns.text, "常来啊!\n");
		SendRspns(tcps, &rspns);
		return 0;


	}

	return 1;

}

//发送回复报文
int SendRspns(SOCKET tcps, RspnsPacket* prspns) {
	if (send(tcps, (char *)prspns, sizeof(RspnsPacket), 0) == SOCKET_ERROR) {
		printf("与客户端失去连接。\n");
		return 0;
	}
	return 1;
}

//接收命令报文
//tcps:控制连接套接字
//pCmd:用于存储返回的命令报文
//返回值:0表示有错或者连接已经断开,1表示正常
int RecvCmd(SOCKET tcps, char* pCmd) {					//used to receive command from client
	int nRet;
	int left = sizeof(CmdPacket);

	//从控制连接中读取数据,大小为 sizeof(CmdPacket):
	while (left) {
		nRet = recv(tcps, pCmd, left, 0);
		if (nRet == SOCKET_ERROR) {
			printf("从客户端接受命令时发生未知错误!\n");
			return 0;
		}
		if (!nRet) {
			printf("客户端关闭了连接!\n");
			return 0;
		}

		left -= nRet;
		pCmd += nRet;
	}
	return 1;   //成功获取命令报文
}


//发送一项文件信息:
int SendFileRecord(SOCKET datatcps, WIN32_FIND_DATA* pfd) {                    //used to send response to client
	char filerecord[MAX_PATH + 32];
	FILETIME ft;
	FileTimeToLocalFileTime(&pfd->ftLastWriteTime, &ft);
	SYSTEMTIME lastwtime;
	FileTimeToSystemTime(&ft, &lastwtime);
	char* dir = (char*)(pfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY ? "<DIR>" : "");
	sprintf(filerecord, "%04d-%02d-%02d%02d:%02d   %5s   %10d   %-20s\n",
		lastwtime.wYear,
		lastwtime.wMonth,
		lastwtime.wDay,
		lastwtime.wHour,
		lastwtime.wMinute,
		dir,
		pfd->nFileSizeLow,
		pfd->cFileName);
	if (send(datatcps, filerecord, strlen(filerecord), 0) == SOCKET_ERROR) {
		printf("发送文件列表时发生未知错误!\n");
		return 0;

	}
	return 1;
}


//发送文件列表信息
//datatcps:数据连接套接字
//返回值:0表示出错,1表示正常
int SendFileList(SOCKET datatcps) {
	HANDLE hff;
	WIN32_FIND_DATA fd;

	//搜索文件
	hff = FindFirstFile("*", &fd);
	if (hff == INVALID_HANDLE_VALUE)  //发生错误
	{
		const char* errstr = "不能列出文件!\n";
		printf("文件列表输出失败!\n");
		if (send(datatcps, errstr, strlen(errstr), 0) == SOCKET_ERROR) {
			printf("发送给文件列表时发生未知错误!\n");
		}
		closesocket(datatcps);			return 0;
	}

	BOOL fMoreFiles = TRUE;
	while (fMoreFiles) {
		//发送此项文件信息:
		if (!SendFileRecord(datatcps, &fd)) {
			closesocket(datatcps);
			return 0;
		}
		//搜索下一个文件
		fMoreFiles = FindNextFile(hff, &fd);
	}
	closesocket(datatcps);
	return 1;
}

//通过数据连接发送文件
int SendFile(SOCKET datatcps, FILE* file) {
	char buf[1024];
	printf("发送文件数据中。。。。。。");
	for (;;) {				//从文件中循环读取数据并发送客户端
		int r = fread(buf, 1, 1024, file);
		if (send(datatcps, buf, r, 0) == SOCKET_ERROR) {
			printf("与客户端失去连接!\n");
			closesocket(datatcps);
			return 0;
		}
		if (r < 1024)   //文件传输结束
		{
			break;
		}
	}
	closesocket(datatcps);
	printf("完成传输!\n");
	return 1;
}

//接收文件
//datatcps:数据连接套接字,通过它来接收数据
//filename:用于存放数据的文件名
int RecvFile(SOCKET datatcps, char* filename) {
	char buf[1024];
	FILE* file = fopen(filename, "wb");
	if (!file) {
		printf("写入文件时发生未知错误!\n");
		fclose(file);
		closesocket(datatcps);
		return 0;
	}
	printf("接受文件数据中。。。。。。");
	while (1) {
		int r = recv(datatcps, buf, 1024, 0);
		if (r == SOCKET_ERROR) {
			printf("从客户端接受文件时发生未知错误!\n");
			fclose(file);
			closesocket(datatcps);
			return 0;
		}
		if (!r) {
			break;
		}
		fwrite(buf, 1, r, file);
	}
	fclose(file);
	closesocket(datatcps);
	printf("完成传输!\n");
	return 1;
}

//检测文件是否存在:
int FileExists(const char *filename)
{
	WIN32_FIND_DATA fd;
	if (FindFirstFile(filename, &fd) == INVALID_HANDLE_VALUE)
		return 0;
	return 1;
}

3.客户端

头文件:(sizes.h)

#pragma once

//服务器侦听控制连接请求的端口
#define CMD_PORT 5858
//客户机侦听数据连接请求的端口
#define DATA_PORT 5850
//命令报文参数缓存的大小
#define CMD_PARAM_SIZE 256
//回复报文消息缓存的大小
#define RSPNS_TEXT_SIZE 256
#define BACKLOG 10
#define DATA_BUFSIZE 4096

//命令类型
typedef enum {
	LS, PWD, CD, DOWN, UP, QUIT
} CmdID;

//命令报文,从客户端发往服务器
typedef struct _CmdPacket {
	CmdID cmdid;
	char param[CMD_PARAM_SIZE];
} CmdPacket;

//回复报文的类型
typedef enum {
	OK, ERR
} RspnsID;

//回复报文,从服务器发往客户端
typedef struct _RspnsPacket {
	RspnsID rspnsid;
	char text[RSPNS_TEXT_SIZE];
} RspnsPacket;

源文件:(客户端.cpp)

#include <WinSock2.h>
#include <windows.h>
#include "sizes.h"
#include <tchar.h>
#include <iostream>

#pragma comment(lib, "ws2_32.lib")

//读取回复报文
void do_read_rspns(SOCKET fd, RspnsPacket *ptr)
{
	int count = 0;
	int size = sizeof(RspnsPacket);
	while (count < size)
	{
		int nRead = recv(fd, (char *)ptr + count, size - count, 0);
		if (nRead <= 0)
		{
			printf("读取服务器的回复失败!\n");
			closesocket(fd);
			exit(1);
		}
		count += nRead;
	}
}

//发送命令报文
void do_write_cmd(SOCKET fd, CmdPacket *ptr)
{
	int size = sizeof(CmdPacket);
	int flag = send(fd, (char *)ptr, size, 0);
	if (flag == SOCKET_ERROR)
	{
		printf("给服务器发送命令失败!\n");
		closesocket(fd);
		WSACleanup();
		exit(1);
	}
}

//创建数据连接套接字并进入侦听状态
SOCKET create_data_socket()
{
	SOCKET sockfd;
	struct sockaddr_in my_addr;
	//创建用于数据连接的套接字
	if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
	{
		printf("创建用于数据连接的套接字失败!\n");
		WSACleanup();
		exit(1);
	}
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(DATA_PORT);
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	memset(&(my_addr.sin_zero), 0, sizeof(my_addr.sin_zero));

	//绑定
	if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == SOCKET_ERROR)
	{
		int err = WSAGetLastError();
		printf("绑定地址失败,错误代码:%d\n", err);
		closesocket(sockfd);
		WSACleanup();
		exit(1);
	}

	//侦听数据连接请求
	if (listen(sockfd, 1) == SOCKET_ERROR)
	{
		printf("监听数据连接失败!\n");
		closesocket(sockfd);
		WSACleanup();
		exit(1);
	}
	return sockfd;
}

//处理list命令
void list(SOCKET sockfd)
{
	int sin_size;
	int nRead;
	CmdPacket cmd_packet;
	SOCKET newsockfd, data_sockfd;
	struct sockaddr_in their_add;
	char data_buf[DATA_BUFSIZE];

	//创建数据连接
	newsockfd = create_data_socket();
	//构建命令报文并发送至服务器
	cmd_packet.cmdid = LS;//没有参数
	do_write_cmd(sockfd, &cmd_packet);
	sin_size = sizeof(struct sockaddr_in);
	//接受服务器的数据连接请求
	if ((data_sockfd = accept(newsockfd, (struct sockaddr*)&their_add, &sin_size)) == INVALID_SOCKET)
	{
		printf("获取文件列表失败!\n");
		closesocket(newsockfd);
		closesocket(sockfd);
		WSACleanup();
		exit(1);
	}

	//每次读到多少数据就显示多少,直到数据连接断开
	while (true)
	{
		nRead = recv(data_sockfd, data_buf, DATA_BUFSIZE - 1, 0);
		if (nRead == SOCKET_ERROR)
		{
			printf("读取服务器回复失败!\n");
			closesocket(data_sockfd);
			closesocket(newsockfd);
			closesocket(sockfd);
			WSACleanup();
			exit(1);
		}

		if (nRead == 0)//数据读取结束
			break;

		//显示数据
		data_buf[nRead] = '\0';
		printf("%s", data_buf);

	}
	closesocket(data_sockfd);
	closesocket(newsockfd);
}
//处理pwd命令:
void pwd(int sockfd)
{
	CmdPacket cmd_packet;
	RspnsPacket rspns_packet;

	cmd_packet.cmdid = PWD;
	//发送命令报文并读取回复:
	do_write_cmd(sockfd, &cmd_packet);
	do_read_rspns(sockfd, &rspns_packet);
	printf("%s\n", rspns_packet.text);
}

//处理cd命令:
void cd(int sockfd)
{
	CmdPacket cmd_packet;
	RspnsPacket rspns_packet;


	cmd_packet.cmdid = CD;
	scanf("%s", cmd_packet.param);

	//发送命令报文并读取回复:
	do_write_cmd(sockfd, &cmd_packet);
	do_read_rspns(sockfd, &rspns_packet);
	if (rspns_packet.rspnsid == ERR)
		printf("%s", rspns_packet.text);
}


//处理down命令,即下载文件:
void get_file(SOCKET sockfd)
{
	FILE *fd;
	char data_buf[DATA_BUFSIZE];

	CmdPacket cmd_packet;
	RspnsPacket rspns_packet;

	SOCKET newsockfd, data_sockfd;
	struct sockaddr_in their_addr;
	int sin_size;
	int count;

	//设置命令报文:
	cmd_packet.cmdid = DOWN;
	scanf("%s", cmd_packet.param);

	//打开或者创建本地文件以供写数据:
	fd = fopen(cmd_packet.param, "wb");//使用二进制方程
	if (fd == NULL)
	{
		printf("打开文件%s来写入失败!\n", cmd_packet.param);
		return;
	}

	//创建数据连接并侦听服务器的连接请求:
	newsockfd = create_data_socket();

	//发送报文请求:
	do_write_cmd(sockfd, &cmd_packet);

	//读取回复报文:
	do_read_rspns(sockfd, &rspns_packet);
	if (rspns_packet.rspnsid == ERR)
	{
		printf("%s", rspns_packet.text);
		closesocket(newsockfd);

		fclose(fd);
		//删除文件:
		DeleteFile(cmd_packet.param);
		return;
	}

	sin_size = sizeof(struct sockaddr_in);
	//等待接受服务器的连接请求
	if ((data_sockfd = accept(newsockfd, (struct sockaddr *)&their_addr, &sin_size)) == INVALID_SOCKET)
	{
		printf("获取文件失败!\n");
		closesocket(newsockfd);

		fclose(fd);
		//删除文件:
		DeleteFile(cmd_packet.param);
		return;
	}

	//循环读取网络数据并写入文件:
	while ((count = recv(data_sockfd, data_buf, DATA_BUFSIZE, 0)) > 0)
		fwrite(data_buf, sizeof(char), count, fd);

	closesocket(data_sockfd);
	closesocket(newsockfd);
	fclose(fd);
}

//处理put命令,即上传文件
void put_file(SOCKET sockfd)
{
	FILE *fd;
	CmdPacket cmd_packet;
	RspnsPacket rspns_packet;
	char data_buf[DATA_BUFSIZE];

	SOCKET newsockfd, data_sockfd;
	struct sockaddr_in their_addr;
	int sin_size;
	int count;
	cmd_packet.cmdid = UP;
	scanf("%s", cmd_packet.param);

	//打开本地文件用于读取数据
	fd = fopen(cmd_packet.param, "rb");
	if (fd == NULL)
	{
		printf("打开文件%s来读取数据失败!\n", cmd_packet.param);
		return;
	}

	//创建数据连接套接字并进入侦听状态;
	newsockfd = create_data_socket();

	//发送命令报文
	do_write_cmd(sockfd, &cmd_packet);

	//读取回复报文
	do_read_rspns(sockfd, &rspns_packet);
	if (rspns_packet.rspnsid == ERR)
	{
		printf("%s", rspns_packet.text);
		closesocket(newsockfd);
		fclose(fd);
		return;
	}

	sin_size = sizeof(struct sockaddr_in);
	//准备接受数据连接
	if ((data_sockfd = accept(newsockfd, (struct sockaddr *)&their_addr, &sin_size)) == INVALID_SOCKET)
	{
		printf("上传文件传输错误!\n");
		closesocket(newsockfd);
		fclose(fd);
		return;
	}
	//循环从文件中读取数据并发给服务器
	while (true)
	{
		count = fread(data_buf, sizeof(char), DATA_BUFSIZE, fd);
		send(data_sockfd, data_buf, count, 0);
		if (count < DATA_BUFSIZE)//数据已经读完或者发生cuowu
			break;
	}

	closesocket(data_sockfd);
	closesocket(newsockfd);
	fclose(fd);
}

//处理退出命令
void quit(int sockfd)
{
	CmdPacket cmd_packet;
	RspnsPacket rspns_packet;

	cmd_packet.cmdid = QUIT;
	do_write_cmd(sockfd, &cmd_packet);
	do_read_rspns(sockfd, &rspns_packet);
	printf("%s", rspns_packet.text);
	getchar();
}

void main()
{
	SOCKET sockfd;
	struct sockaddr_in their_addr;
	char cmd[10];
	RspnsPacket rspns_packet;

	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(2, 2);
	//Winsock初始化
	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0)
	{
		printf("WinSock初始化失败!\n");
		return;
	}

	//确认WindSock DLL的版本是2.2
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
	{
		printf("WindSock版本不是2.2!\n");
		WSACleanup();
		return;
	}

	//创建用于控制谅解的socket
	sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sockfd == INVALID_SOCKET)
	{
		printf("创建套接字失败!\n");
		WSACleanup();
		exit(1);
	}
	their_addr.sin_family = AF_INET;
	their_addr.sin_port = htons(CMD_PORT);
	their_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	memset(&(their_addr.sin_zero), 0, sizeof(their_addr.sin_zero));

	//连接服务器
	if (connect(sockfd, (struct sockaddr*)&their_addr, sizeof(struct sockaddr)) == SOCKET_ERROR)
	{
		printf("连接服务器失败!\n");
		closesocket(sockfd);
		WSACleanup();
		exit(1);
	}

	//连接成功后,首先接受服务器发回的消息
	do_read_rspns(sockfd, &rspns_packet);
	printf("%s", rspns_packet.text);

	//主循环:读取用户输入并分配执行
	while (true)
	{
		scanf("%s", cmd);
		switch (cmd[0])
		{
		case 'l'://处理List命令
			list(sockfd);
			break;
		case 'p'://处理pwd命令
			pwd(sockfd);
			break;
		case 'c'://处理cd命令
			cd(sockfd);
			break;
		case 'd'://处理down命令
			get_file(sockfd);
			break;
		case 'u'://处理up命令
			put_file(sockfd);
			break;
		case 'q'://处理quit命令
			quit(sockfd);
			break;
		default:
			printf("不存在的命令!\n");
			break;
		}
		if (cmd[0] == 'q')
			break;
	}
	WSACleanup();
}

猜你喜欢

转载自blog.csdn.net/hanjmm/article/details/89093530