C++ socket实现miniFTP

2025-05-27 0 31

本文实例为大家分享了C++ socket实现miniFTP的方法,供大家参考,具体内容如下

客户端:

C++ socket实现miniFTP

服务端:

C++ socket实现miniFTP

建立连接

连接使用 TCP 连接,服务器和客户端分别创建自己的套接字一端,服务器等待连接,客户端发起连接(并指定服务器 ip)。在两者端口号一致且不被占用的情况下,连接建立。
在整个过程中,服务器对每一个来访的客户端建立一个连接,在客户未请求与服务器断开时,该连接一直存在,用户可以不断向服务器发出请求。(持久性、流水线型连接 )
客户端断开后,关闭客户端的套接字部分,服务器继续等待新的连接。服务器一次只能处理一个客户端的连接,不支持并发访问。

PDU 格式

由于 ftp 应当支持几乎任意类型文件,而几乎所有类型文件都能用二进制来解析,所以我们采用了二进制的格式来读取以及写入文件。在整个过程中,我们并不关心文件的具体内容,也无需在程序中解析文件,而是将其当作数据流看待。
受到缓存区大小的限制,我们无法一次性传输整个文件,所以我们将文件按缓存区大小拆分成数据包分批发送,我们可以将数据及时从缓存区写入文件,这样就让出了缓存区空间。数据包仅仅包含数据,不包含头部或尾部信息。
此外,接收文件时,recv()函数将会循环调用,因此,我们需要一个信号来通知什么时候发送完毕。
一个想法是发送终止信号,这是可行的,但更好的方法是在一开始发送文件总字节数,让接收方根据剩余字节大小判断什么时候接收完毕。因为在写入文件时,我们需要指定写入的字节数,尤其是在发来的数据流字节数不等于缓冲区大小时。写入字节数的错误会导致文件受损。

接收确认

我们知道 TCP 是可靠传输协议,它采取了一系列措施来保证传输不会出错。所以在使用 TCP 连接时,我们相信数据在链路层上没有出差错,它一定会成功发送到对方手上。但是在客户端接收服务器发来的文件的时候,我们仍然需要服务器发来确认信息。原因在于,虽然我们可以保证链路层不出错,但是我们无法保证应用层不出错。例如,客户端可能会给出错误的文件名,因为接收不到服务器发来的信息,所以会陷入空等状态。

ftpClient.h

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28
#pragma

#include<winsock.h>

class ftpClient

{

private:

enum {

SERVER_PORT = 9999,

BUFFER_SIZE = 4096

};

sockaddr_in serverChannel;

char buffer[BUFFER_SIZE];

int serverSocket;

int clientSocket;

bool isConnect;

char name[50];

bool getFile();

bool putFile();

bool acknowledge();

bool sendRequest(char* instruction);

bool connect2Host(const char* hostName);

bool getWorkDir();

public:

ftpClient();

~ftpClient();

void start();

};

ftpClient.cpp

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315
#define _CRT_SECURE_NO_WARNINGS

#include"ftpClient.h"

#include<cstdio>

#include<io.h>

#include<cstring>

#include<fstream>

ftpClient::ftpClient()

{

WORD wVersionRequested;

WSADATA wsaData;

int ret;

//WinSock初始化:

wVersionRequested = MAKEWORD(2, 2);//希望使用的WinSock DLL的版本

ret = WSAStartup(wVersionRequested, &wsaData);

if (ret != 0)

{

printf("WSAStartup() failed!\\n");

}

//确认WinSock DLL支持版本2.2:

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

{

WSACleanup();

printf("Invalid Winsock version!\\n");

}

isConnect = false;

}

void ftpClient::start()

{

char c[100];

char d[100];

printf("这里是FTP客户端,您可以输入help查看操作方法,输入quit退出客户端\\n");

while (1) {

scanf("%s", c);

if (strcmp(c, "help") == 0) {

printf("get [fileName] -- 下载文件\\n"

"put [fileName] -- 上传文件\\n"

"ftp [ip] -- 登录FTP\\n"

"pwd -- 显示服务器当前工作文件夹\\n"

"cd [dirName] -- 更改当前文件夹\\n"

"close -- 关闭与当前ftp的连接\\n"

"quit -- 退出客户端\\n"

);

}

else if (strcmp(c, "get") == 0) {

scanf("%s", d);

strcat(c, " ");

strcat(c, d);

if (!isConnect) {

printf("you haven't connected to any server!\\n");

}

else sendRequest(c);

}

else if (strcmp(c, "put") == 0) {

scanf("%s", d);

strcat(c, " ");

strcat(c, d);

if (!isConnect) {

printf("you haven't connected to any server!\\n");

}

else sendRequest(c);

}

else if (strcmp(c, "ftp") == 0) {

scanf("%s", d);

if (!isConnect&&connect2Host(d)) {

isConnect = true;

}

else if(isConnect){

printf("you have already connected to server\\n"

"please close the connection before connect to a new server\\n");

}

}

else if (strcmp(c, "pwd") == 0) {

if (!isConnect) {

printf("you haven't connected to any server!\\n");

}

else sendRequest(c);

}

else if (strcmp(c, "cd") == 0) {

scanf("%s", d);

strcat(c, " ");

strcat(c, d);

if (!isConnect) {

printf("you haven't connected to any server!\\n");

}

else sendRequest(c);

}

else if (strcmp(c, "quit") == 0) {

if (isConnect) {

strcpy(c, "close");

isConnect = false;

send(clientSocket, c, strlen(c) + 1, 0);

closesocket(clientSocket);

}

break;

}

else if (strcmp(c, "close") == 0) {

if (isConnect) {

isConnect = false;

send(clientSocket, c, strlen(c) + 1, 0);

closesocket(clientSocket);

}

}

else {

printf("syntex error\\n");

}

}

}

bool ftpClient::connect2Host(const char* hostName)

{

//创建socket

clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (clientSocket < 0) {

printf("cannot create socket\\n");

return false;

}

else printf("successfully create socket\\n");

memset(&serverChannel, 0, sizeof(serverChannel));//初始化为0

serverChannel.sin_family = AF_INET;//channel协议家族AF_INET

serverChannel.sin_addr.S_un.S_addr = inet_addr(hostName);//地址

serverChannel.sin_port = htons(SERVER_PORT);//服务器端口

//建立连接

serverSocket = connect(clientSocket, (sockaddr*)&serverChannel, sizeof(serverChannel));

if (serverSocket < 0) {

printf("cannot connect to the host\\n");

return false;

}

else {

printf("successfully connect to the host\\n");

return true;

}

}

bool ftpClient::sendRequest(char* instruction)

{

int r = send(clientSocket, instruction, strlen(instruction) + 1, 0);

if (r == SOCKET_ERROR) {

printf("request failed\\n");

return false;

}

else {

printf("request success\\n");

char opt[5];

int i = 0, j = 0;

while (instruction[i] != ' '&&instruction[i] != '\\0') {

opt[i] = instruction[i];

i++;

}

opt[i] = '\\0';

i++;

while (instruction[i] != '\\0') {

name[j] = instruction[i];

i++, j++;

}

name[j] = '\\0';

if (strcmp(opt, "get") == 0) {

if (getFile()) {

printf("successfully download\\n");

}

else printf("download failed\\n");

}

else if (strcmp(opt, "put") == 0) {

if (putFile()) {

printf("successfully upload\\n");

}

else printf("upload failed\\n");

}

else if (strcmp(opt, "pwd") == 0) {

if (!getWorkDir())

printf("get work directory failed\\n");

}

else if (strcmp(opt, "cd") == 0) {

printf("operation finished\\n");

}

else {

printf("syntex error\\n");

return false;

}

return true;

}

}

bool ftpClient::getFile()

{

memset(buffer, 0, sizeof(buffer));

int ret;

char length[20];

ret = recv(clientSocket, length, sizeof(length), 0);

if (ret == SOCKET_ERROR) {

return false;

}

else if (strcmp(length, "NAK") == 0) {

return false;

}

int size = atoi(length);

std::ofstream out;

out.open(name, std::ios::binary);

if (!out) {

printf("cannot save the file\\n");

return false;

}

while (size>0) {

ret = recv(clientSocket, buffer, BUFFER_SIZE, 0);

int s = size < BUFFER_SIZE ? size : BUFFER_SIZE;

if (ret == SOCKET_ERROR) {

out.close();

return false;

}

else if (strcmp(buffer, "NAK") == 0) {

out.close();

return false;

}

else {

out.write(buffer, s);

}

size -= BUFFER_SIZE;

}

out.close();

return acknowledge();

}

bool ftpClient::putFile()

{

std::ifstream in;

//打开文件

in.open(name, std::ios::binary);

if (!in) {

printf("cannot open the file\\n");

return false;

}

memset(buffer, 0, sizeof(buffer));

//得到文件的字节数

in.seekg(0, std::ios_base::end);

int sp = in.tellg();

int total_size = 0;

int r;

char length[20];

sprintf(length, "%d", sp);

//发送字节

r = send(clientSocket, length, sizeof(length), 0);

if (r == SOCKET_ERROR) {

return false;

}

while (sp > 0) {

in.clear();

in.seekg(total_size, std::ios_base::beg);

memset(buffer, 0, sizeof(buffer));

//读取文件

in.read(buffer, sizeof(buffer));

int size = sp < BUFFER_SIZE ? sp : BUFFER_SIZE;

total_size += size;

//发送文件

r = send(clientSocket, buffer, size, 0);

sp -= size;

if (r == SOCKET_ERROR) {

in.close();

return false;

}

}

in.close();

}

bool ftpClient::getWorkDir() {

printf("getWorkDir\\n");

memset(buffer, 0, sizeof(buffer));

int ret;

char length[20];

ret = recv(clientSocket, length, sizeof(length), 0);

if (ret == SOCKET_ERROR) {

return false;

}

int size = atoi(length);

while (size>0) {

ret = recv(clientSocket, buffer, BUFFER_SIZE, 0);

if (ret == SOCKET_ERROR) {

return false;

}

else {

printf("%s", buffer);

}

size -= BUFFER_SIZE;

}

return true;

}

bool ftpClient::acknowledge()

{

int ret = recv(clientSocket, buffer, BUFFER_SIZE, 0);

if (ret > 0) {

if (strcmp(buffer, "NAK") == 0)return false;

else if (strcmp(buffer, "ACK") == 0)return true;

}

}

ftpClient::~ftpClient()

{

if (isConnect) {

isConnect = false;

char c[6];

strcpy(c, "close");

send(clientSocket, c, strlen(c) + 1, 0);

closesocket(clientSocket);

}

}

main.cpp

?

1

2

3

4

5

6

7

8

9

10

11

12
#define _CRT_SECURE_NO_WARNINGS

#define _WINSOCK_DEPRECATED_NO_WARNINGS

#pragma(lib,"ws2_32.lib")

#include"ftpClient.h"

#include<stdio.h>

int main()

{

ftpClient a;

a.start();

return 0;

}

ftpServer.h

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28
#pragma once

#include<winsock.h>

class ftpServer

{

private:

enum {

SERVER_PORT = 9999,

BUFFER_SIZE = 4096,

QUEUE_SIZE = 10

};

char buffer[BUFFER_SIZE];

sockaddr_in serverChannel;

char name[50];

char workDir[100]; //store like C:\\Users MARK:字符串末没有斜线!!

int serverSocket; //socket

int clientSocket;

bool sendFile();

bool receiveFile();

bool doPwd();

bool doCd();

bool isValidPath(char* path);

public:

ftpServer();

bool start();//开启服务器

};

ftpServer.cpp

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358
#define _CRT_SECURE_NO_WARNINGS

#include"ftpServer.h"

#include<cstdio>

#include<cstdlib>

#include<fstream>

#include<cstring>

ftpServer::ftpServer()

{

WORD wVersionRequested;

WSADATA wsaData;

int ret;

//WinSock初始化:

wVersionRequested = MAKEWORD(2, 2);//希望使用的WinSock DLL的版本

ret = WSAStartup(wVersionRequested, &wsaData);

if (ret != 0)

{

printf("WSAStartup() failed!\\n");

}

//确认WinSock DLL支持版本2.2:

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

{

WSACleanup();

printf("Invalid Winsock version!\\n");

}

//workDir初始化为当前路径

system("cd > tempFile");

std::ifstream in("tempFile", std::ifstream::in);

in >> workDir;

in.close();

}

bool ftpServer::start()

{

int on = 1;

//初始化服务器

memset(&serverChannel, 0, sizeof(serverChannel));

serverChannel.sin_family = AF_INET;

serverChannel.sin_addr.s_addr = htonl(INADDR_ANY);

serverChannel.sin_port = htons(SERVER_PORT);

//创建套接字

this->serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (serverSocket < 0) {

printf("cannot create socket\\n");

return false;

}

else printf("successfully create socket\\n");

setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR,

(char*)&on, sizeof(on));

//绑定

int b = bind(serverSocket, (sockaddr*)&serverChannel,

sizeof(serverChannel));

if (b < 0) {

printf("bind error\\n");

return false;

}

else printf("successfully bind\\n");

//监听

int l = listen(serverSocket, QUEUE_SIZE);

if (l < 0) {

printf("listen failed\\n");

return false;

}

else printf("successfully listen\\n");

int len = sizeof(serverChannel);

//服务器等待连接

while (1) {

printf("waiting for connection...\\n");

//接受一个连接

clientSocket = accept(serverSocket, (sockaddr*)&serverChannel,

&len);

if (clientSocket < 0) {

printf("accept failed\\n");

}

else {

printf("successfully connect\\n");

while (1) {

memset(buffer, 0, sizeof(buffer));

int ret;

ret = recv(clientSocket, buffer, BUFFER_SIZE, 0);

if (ret == SOCKET_ERROR) {

printf("receive failed\\n");

}

else {

char opt[50];

printf("successfully receive\\n");

int i = 0, j = 0;

printf("buffer = %s\\n", buffer);

while (buffer[i] != ' '&&buffer[i] != '\\0') {

opt[i] = buffer[i];

i++;

}

opt[i] = '\\0';

if (buffer[i] != '\\0') {

i++;

}

while (buffer[i] != '\\0') {

name[j] = buffer[i];

i++, j++;

}

name[j] = '\\0';

if (strcmp(opt, "get") == 0) {

char ret[4];

if (!sendFile()) {

strcpy(ret, "NAK");

send(clientSocket, ret, sizeof(ret), 0);

}

else {

strcpy(ret, "ACK");

send(clientSocket, ret, sizeof(ret), 0);

}

}

else if (strcmp(opt, "put") == 0) {

receiveFile();

}

else if (strcmp(opt, "pwd") == 0) {

doPwd();

}

else if (strcmp(opt, "cd") == 0) {

doCd();

}

else if (strcmp(opt, "close") == 0) {

break;

}

else {

printf("syntex error\\n");

}

}

}

}

}

return true;

}

bool ftpServer::sendFile()

{

std::ifstream in;

char path[100];

strcpy(path, workDir);

strcat(path, "\\\\");

strcat(path, name);

in.open(path, std::ios::binary);

if (!in) {

printf("cannot open the file\\n");

return false;

}

memset(buffer, 0, sizeof(buffer));

in.seekg(0, std::ios_base::end);

int sp = in.tellg();

int total_size = 0;

int r;

char length[20];

sprintf(length, "%d", sp);

r = send(clientSocket, length, sizeof(length), 0);

if (r == SOCKET_ERROR) {

printf("send failed\\n");

return false;

}

else {

printf("send success\\n");

}

while (sp > 0) {

in.clear();

in.seekg(total_size, std::ios_base::beg);

memset(buffer, 0, sizeof(buffer));

in.read(buffer, sizeof(buffer));

int size = sp < BUFFER_SIZE ? sp : BUFFER_SIZE;

total_size += size;

r = send(clientSocket, buffer, size, 0);

sp -= size;

if (r == SOCKET_ERROR) {

printf("send failed\\n");

return false;

}

else {

printf("send success\\n");

}

}

in.close();

return true;

}

bool ftpServer::receiveFile()

{

char path[100];

strcpy(path, workDir);

strcat(path, "\\\\");

strcat(path, name);

memset(buffer, 0, sizeof(buffer));

int ret;

char length[20];

ret = recv(clientSocket, length, sizeof(length), 0);

if (ret == SOCKET_ERROR) {

printf("receive failed\\n");

return false;

}

else {

printf("successfully receive\\n");

}

int size = atoi(length);

std::ofstream out;

out.open(path, std::ios::binary);

if (!out) {

printf("cannot save the file\\n");

return false;

}

while (size>0) {

int s = size < BUFFER_SIZE ? size : BUFFER_SIZE;

ret = recv(clientSocket, buffer, BUFFER_SIZE, 0);

if (ret == SOCKET_ERROR) {

printf("receive failed\\n");

break;

}

else {

printf("successfully receive\\n");

out.write(buffer, s);

}

size -= BUFFER_SIZE;

}

out.close();

return true;

}

bool ftpServer::doPwd() {

char temCMD[150];

memset(temCMD, 0, sizeof(temCMD));

strcat(temCMD, "echo ");

strcat(temCMD, workDir);

strcat(temCMD, " > tempFile");

system(temCMD);

memset(temCMD, 0, sizeof(temCMD));

strcat(temCMD, "dir /b ");

strcat(temCMD, workDir);

strcat(temCMD, " >> tempFile");

system(temCMD);

std::ifstream in("tempFile", std::fstream::in);

if (!in) {

printf("cannot open the file\\n");

return false;

}

memset(buffer, 0, sizeof(buffer));

in.seekg(0, std::ios_base::end);

int sp = in.tellg();

int total_size = 0;

int r;

char length[20];

sprintf(length, "%d", sp);

r = send(clientSocket, length, sizeof(length), 0);

if (r == SOCKET_ERROR) {

printf("send failed\\n");

return false;

}

else {

printf("send success\\n");

}

while (sp > 0) {

in.clear();

in.seekg(total_size, std::ios_base::beg);

memset(buffer, 0, sizeof(buffer));

in.read(buffer, sizeof(buffer));

int size = sp < BUFFER_SIZE ? sp : BUFFER_SIZE;

total_size += size;

printf("transfer size = %d\\n", total_size);

r = send(clientSocket, buffer, size, 0);

sp -= size;

if (r == SOCKET_ERROR) {

printf("send failed\\n");

return false;

}

else {

printf("send success\\n");

}

}

in.close();

return true;

}

bool ftpServer::isValidPath(char* path) {

char temCMD[100];

memset(temCMD, 0, sizeof(temCMD));

strcat(temCMD, "cd ");

strcat(temCMD, path);

int res = system(temCMD);

return res == 0;

}

bool ftpServer::doCd() {

for (int i = 0; name[i] != '\\0'; ++i) {

if (name[i] == '/')

name[i] = '\\\\';

}

if (name[0] == '.'&&name[1] == '.') {

char temDir[100];

strcpy(temDir, workDir);

for (int i = sizeof(temDir); i >= 0; --i) {

if (temDir[i] == '\\\\') {

temDir[i] = '\\0';

break;

}

}

strcat(temDir, name + 2);

if (isValidPath(temDir)) {

strcpy(workDir, temDir);

}

else {

return false;

}

}

else if (name[0] == '.'&&name[1] != '.') {

char temDir[100];

strcpy(temDir, workDir);

strcat(temDir, name + 1);

if (isValidPath(temDir)) {

strcpy(workDir, temDir);

}

else {

return false;

}

}

else if (name[1] == ':') {

if (isValidPath(name)) {

strcpy(workDir, name);

}

else {

return false;

}

}

else {

char temDir[100];

strcpy(temDir, workDir);

strcat(temDir, "\\\\");

strcat(temDir, name);

if (isValidPath(temDir)) {

strcpy(workDir, temDir);

}

else {

return false;

}

}

return true;

}

main.cpp

?

1

2

3

4

5

6

7
#include"ftpServer.h"

#pragma(lib,"ws2_32.lib")

int main()

{

ftpServer f;

f.start();

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持快网idc。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 C++ socket实现miniFTP https://www.kuaiidc.com/74395.html

相关文章

发表评论
暂无评论