模拟比特洪流协议

发布时间 2023-12-16 20:29:19作者: WEI苦手

一、实验目标

       首先将一个图形文件划分成指定大小的数据块。在一台主机下模拟五个应用进程,其中有四个peer,分别为peer1,peer2,peer3,peer4,还有一个tracker。将上述的图片数据块按要求分配到三个节点(peer1,peer2,peer3)上,peer4从tracker上获取三个节点的数据块信息。最后从三个节点(peer1,peer2,peer3)传输图片文件的不同块到peer4上,使得该节点获取完整的图片文件。

二、实验环境

      编程测试环境:软件:Dev C++  语言:标准C语言

实验结构图:

 

假定peer1上存放数据块1,3,5,7

peer2上存放数据块9,10,11

peer3上存放数据块2,4,6,8

三、方案流程

实验包含以下组件:

Tracker服务器:负责记录哪些节点拥有文件的哪些部分。收到请求即发送相关信息。

节点(Peers):拥有文件的一部分,并与其他节点交换数据。也可以向Tracker服务器请求其他拥有文件部分的节点信息。

1.初始化

选择一个图片文件,并将其分割为11个小块(例如,每个块为256KB)。

设置一个Tracker服务器,并启动它。

2.创建节点(Peers)

启动4个节点,命名为peer1,peer2,peer3,peer4。

将数据块按(4,3,4)分配给Peer1,Peer2,Peer3

3.发送文件

       让Peer4请求Tracker获取Peer1,Peer2,Peer3各节点上的数据块情况。从Peer1,Peer2,Peer3获取图片的数据块。得到所有数据块后拼接数据块得到完整的图片。

 

 1 #include <windows.h>
 2 #include <iostream>
 3 #include <winsock.h>
 4 using namespace std;
 5 #define NO_FLAGS_SET 0
 6 #define FILE_ID_START 1
 7 #define FILE_ID_END 4
 8 #define FILE_BLOCK_SIZE 409600
 9 #define PORT (u_short) 44966
10 #define DEST_IP_ADDR "127.0.0.1" //Server address
11 
12 INT main(VOID)
13 {
14   WSADATA Data;
15   SOCKADDR_IN destSockAddr;
16   SOCKET destSocket;
17   unsigned long destAddr;
18   int status;
19   int numsnt;
20   
21   /* initialize the Windows Socket DLL */
22   status=WSAStartup(MAKEWORD(1, 1), &Data);
23   if (status != 0)
24     cerr << "ERROR: WSAStartup unsuccessful"
25       << endl;
26   /* convert IP address into in_addr form */
27   destAddr=inet_addr(DEST_IP_ADDR);
28   /* copy destAddr into sockaddr_in structure */
29   memcpy(&destSockAddr.sin_addr,
30     &destAddr, sizeof(destAddr));
31   /* specify the port portion of the address */
32   destSockAddr.sin_port=htons(PORT);
33   /* specify the address family as Internet */
34   destSockAddr.sin_family=AF_INET;
35 
36   /* create a socket */
37   destSocket=socket(AF_INET, SOCK_STREAM, 0);
38   if (destSocket == INVALID_SOCKET)
39   {
40     cerr << "ERROR: socket unsuccessful" << endl;
41     status=WSACleanup();
42     if (status == SOCKET_ERROR)
43       cerr << "ERROR: WSACleanup unsuccessful" 
44         << endl;
45     return(1);
46   }
47 
48   cout << "Trying to connect to IP Address: "
49     << DEST_IP_ADDR << endl;
50 
51   /* connect to the server */
52   status=connect(destSocket,
53     (LPSOCKADDR) &destSockAddr,
54     sizeof(destSockAddr));
55   if (status == SOCKET_ERROR)
56   {
57     cerr << "ERROR: connect unsuccessful" << endl;
58     status=closesocket(destSocket);
59     if (status == SOCKET_ERROR)
60       cerr << "ERROR: closesocket unsuccessful"
61         << endl;
62     status=WSACleanup();
63     if (status == SOCKET_ERROR)
64       cerr << "ERROR: WSACleanup unsuccessful"
65         << endl;
66     return(1);
67   }
68 
69   cout << "Connected..." << endl;
70 
71 
72     int id = FILE_ID_START;            // 文件块编号
73     FILE *fp;            // 文件块读取指针
74     char fileName[100]; //文件名
75     char path[100];//路径 
76     char buf[FILE_BLOCK_SIZE];
77     sprintf(fileName, "part_%02d", id);
78     while (id <= FILE_ID_END) {    
79         send(destSocket, fileName, strlen(fileName) + 1, 0);// 先发送文件名
80         Sleep(50); 
81         sprintf(path, "%s%s", "C:\\Users\\大梦一场\\Desktop\\peer1\\",fileName);
82         fp = fopen(path, "rb+");
83         int count = fread(buf, 1, FILE_BLOCK_SIZE, fp); // 读取全部元素
84         fclose(fp);
85         send(destSocket, buf, count, 0);                // 发送文件块
86         printf("ClientPeer1 sending %s successfully\n", path);
87         Sleep(3000); // 等待 3 s
88         id++;
89         sprintf(fileName, "part_%02d", id);
90     }
91 
92 }

peer4

#include <windows.h>
#include <iostream>
#include <winsock.h>
using namespace std;
#define NO_FLAGS_SET 0
#define THIS_PORT (u_short) 44967
#define PORT (u_short) 44966
#define DEST_IP_ADDR "127.0.0.1" //Server address
#define FILE_BLOCK_SIZE 409600
#define FILE_BLOCK_NUM 11
#define FILE_NAME_LEN 7
#define DEST_PORT (u_short) 44966
#define CLIENT_NUM 3
char dataBuffer[FILE_BLOCK_SIZE];		// 用于存储接收到的数据
char fileName[100]; //文件名
DWORD ThreadProc(LPVOID clientSock)  
{  
	SOCKET NewConnection = (SOCKET)clientSock;
    char dataBuffer[FILE_BLOCK_SIZE];		// 用于存储接收到的数据
	char fileName[100]; //文件名
	int count;
	FILE *fp = NULL;
	char path[100];//路径 
	while ((count = recv(NewConnection, dataBuffer, sizeof(dataBuffer), 0)) > 0) {	
		if (strlen(dataBuffer) == FILE_NAME_LEN) {		// 发来的是文件名
			strcpy(fileName, dataBuffer);				// 记录文件名
			printf("receving %s\n", fileName);		
		}
		else {
			sprintf(path, "%s%s", "C:\\Users\\大梦一场\\Desktop\\peer4\\",fileName);
			fp = fopen(path, "wb");					// 创建文件
			fwrite(dataBuffer, count, 1, fp);
			printf("receving data %s\n", fileName);
			fclose(fp);
		}
	}
  
    return 0;  
}

int main(void)
{
  
  int numsnt;
  char *getInfo="getInfo";
  WSADATA Data;
  SOCKADDR_IN serverSockAddr;
  SOCKADDR_IN clientSockAddr;
  SOCKET serverSock;
  SOCKET clientSock;
  int addrLen=sizeof(SOCKADDR_IN);
  int status;
  int numrcv;
  char buffer[1024];

  /* initialize the Windows Socket DLL */
  status=WSAStartup(MAKEWORD(1, 1), &Data);
  /*初始化Winsock DLL*/
  if (status != 0)
    cerr << "ERROR: WSAStartup unsuccessful" << endl;

  /* zero the sockaddr_in structure */
  
  memset(&serverSockAddr, 0,sizeof(serverSockAddr));
  
  
  /* specify the port portion of the address */
  serverSockAddr.sin_port=htons(PORT);
  /* specify the address family as Internet */
  serverSockAddr.sin_family=AF_INET;
  /* specify that the address does not matter */
  /*INADDR_ANY 的具体含义是,绑定到0.0.0.0。此时,对所有的地址都将是有效的*/
  serverSockAddr.sin_addr.s_addr=htonl(INADDR_ANY);
  /* create a socket */
  serverSock=socket(AF_INET, SOCK_STREAM, 0);
  if (serverSock == INVALID_SOCKET)
    cerr << "ERROR: socket unsuccessful" << endl;

  /* associate the socket with the address */
  status=bind(serverSock, (LPSOCKADDR) &serverSockAddr,
    sizeof(serverSockAddr));
  if (status == SOCKET_ERROR)
    cerr << "ERROR: bind unsuccessful" << endl;

  /* allow the socket to take connections */
  status=listen(serverSock, 1);
  if (status == SOCKET_ERROR)
    cerr << "ERROR: listen unsuccessful" << endl;	
  
  
  int conn=0;
  while(1)
  {
		int clientAddrLen = sizeof(SOCKADDR);	// 求出地址的长度
		// 接收请求(链接客户端),第二个参数是客户端的地址
		if ((clientSock = accept(serverSock, (LPSOCKADDR)&clientSockAddr, &clientAddrLen)) == INVALID_SOCKET)
		{
			printf("accept failed with error %d\n", WSAGetLastError());
			closesocket(clientSock); // 释放客户端连接	
		}
		// 连接客户端成功,打印客户端的ip地址和端口号
		printf("当前已连接:%s:%d\n", inet_ntoa(clientSockAddr.sin_addr), ntohs(clientSockAddr.sin_port));
		// 开启线程处理客户端连接
		CreateThread(NULL, 0, ThreadProc, (LPVOID)clientSock, 0, NULL);
		conn++;
		
		/* 文件的拼接 */
  		if (conn == CLIENT_NUM) { //  接收完3个进程发送的文件
			Sleep(2000);
			printf("Succeeded in accepting all file blocks. \n");
			int id = 1;			// 文件块编号
			FILE *fpr;			// 文件块读取指针
			FILE *fpw = fopen("C:\\Users\\大梦一场\\Desktop\\DarkSoul.jfif", "wb");
			char fileName[100]; //文件名		
			while (id <= FILE_BLOCK_NUM) {
				sprintf(fileName, "C:\\Users\\大梦一场\\Desktop\\peer4\\part_%02d", id);
				fpr = fopen(fileName, "rb+");
				int count = fread(dataBuffer, 1, FILE_BLOCK_SIZE, fpr);
				fwrite(dataBuffer, count, 1, fpw);
				id++;
				fclose(fpr);
			}
			fclose(fpw);
			Sleep(1000);
			printf("DarkSoul.jfif combining succeeded!\n");
		}
    }
}