SOCKET编程实现Client/ Server程序:比特洪流协议模拟

这篇具有很好参考价值的文章主要介绍了SOCKET编程实现Client/ Server程序:比特洪流协议模拟。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 文章来源地址https://www.toymoban.com/news/detail-760060.html

一、引言   

    使用基本的套接字编程技术,以一对基本的TCP协议通信程序为基础,模拟比特洪流(BitTorrent)的分散传输技术完成一个文件的正确传输,使用标准C语言编程。本实验的目的并不是做一个实用的网络程序,而是更好地理解套接字编程原理和P2P技术,重点在特定条件下的实验方案的设计并予以实现。    

   尽可能模拟比特洪流协议,描述文件分散传输实验方案,实现同一个文件内容从多个PEER获取。

   

二、设计思路

   比特洪流的简要介绍

  BitTorrent(简称BT)是一个文件分发协议,每个下载者在下载的同时不断向其他下载者上传已下载的数据。而在FTP,HTTP协议中,每个下载者在下载自己所需文件的同时,各个下载者之间没有交互。当非常多的用户同时访问和下载服务器上的文件时,由于FTP服务器处理能力和带宽的限制,下载速度会急剧下降,有的用户可能访问不了服务器。BT协议与FTP协议不同,特点是下载的人越多,下载速度越快,原因在于每个下载者将已下载的数据提供给其他下载者下载,充分利用了用户的上载带宽。通过一定的策略保证上传速度越快,下载速度也越快。在很短时间内,BitTorrent协议成为一种新的变革技术。

 BitTorrent 的发展依赖于peer-to-peer技术。对等网络 (Peer - to - Peer 简称 P2P) 的研究一直是国外知名学府和知名企业以及研发机构最关注的重点。P2P是近年来互联网最热门的技术,在VoIP、下载、流媒体、协调技术等领域得到飞速发展,被财富杂志评为影响互联网的四大科技之一,甚至被认为是代表无线宽带互联网未来的关键技术。

 

   设计思路

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

三、实验环境

       C语言

实验结构图:

 SOCKET编程实现Client/ Server程序:比特洪流协议模拟

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

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

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

四、编程实现

数据发送方(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");
		}
    }
}

  

运行结果:

SOCKET编程实现Client/ Server程序:比特洪流协议模拟

                                          

SOCKET编程实现Client/ Server程序:比特洪流协议模拟

                                          数据发送

            SOCKET编程实现Client/ Server程序:比特洪流协议模拟

                                       数据接收

 

到了这里,关于SOCKET编程实现Client/ Server程序:比特洪流协议模拟的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • c++ 之 socket udp与tcp client server实现

    socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用打开open – 读写write/read – 关闭close模式来操作。Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭). 说白了Socket是应用层与TCP/IP协议族通

    2023年04月15日
    浏览(29)
  • 基于Springboot整合Socket仿微信实现群聊、私聊功能。实现客户端client,服务端server心跳维护、超时机制【一文通】

    博主介绍: ✌java资深开发工程师、Java领域优质创作者,博客之星、专注于Java技术领域和学生毕业项目实战,面试讲解跟进,高校老师/讲师/同行交流合作✌ 胡广愿景: \\\"比特星球\\\",致力于帮助底层人员找到工作, 让每个底层人员都能找到属于自己的星球。 拓展学习领域,获

    2024年02月19日
    浏览(38)
  • Linux网络编程:socket & fork实现clients/server通信

    UNIX网络编程:socket实现client/server通信 随笔简单介绍了TCP Server服务单客户端的socket通信,但是并未涉及多客户端通信。 对于网络编程肯定涉及到多客户端通信和并发编程 (指在同时有大量的客户链接到同一服务器),故本随笔补充这部分知识。 而且并发并发编程涉及到多进程

    2024年02月05日
    浏览(37)
  • Redis的实现一:c、c++的网络通信编程技术,先实现server和client的通信

    由于,本人是主修java的,所以以下内容可能不是很精通,各位看完后尽可评论。 以下皆是在linux的描述 Socket()函数 :创建用于通信的端点并返回描述符。 它的第一个参数 便是通信域,这里我举出常用的。 AF_INET是ipv4的。 AF_INET6是ipv6的。 它的第二个参数 便是套接字具有指定

    2024年01月16日
    浏览(31)
  • UNIX网络编程:socket & fork()多进程 实现clients/server通信

    UNIX网络编程:socket实现client/server通信 随笔简单介绍了TCP Server服务单客户端的socket通信,但是并未涉及多客户端通信。 对于网络编程肯定涉及到多客户端通信和并发编程 (指在同时有大量的客户链接到同一服务器),故本随笔补充这部分知识。 而且并发并发编程涉及到多进程

    2024年02月06日
    浏览(35)
  • Linux网络编程:socket & fork()多进程 实现clients/server通信

    UNIX网络编程:socket实现client/server通信 随笔简单介绍了TCP Server服务单客户端的socket通信,但是并未涉及多客户端通信。 对于网络编程肯定涉及到多客户端通信和并发编程 (指在同时有大量的客户链接到同一服务器),故本随笔补充这部分知识。 而且并发并发编程涉及到多进程

    2024年02月05日
    浏览(34)
  • 【C语言实现windows环境下Socket编程TCP/IP协议】

    代码是别人的,问题是我的。顺便记录一下遇见的各种问题和我的解决办法。 可能的解决方案: 1、服务端和客户端不在一个局域网,可以开热点,这样就在了。然后ipconfig查看IP地址,就ok了。至于怎么查看在不在就ping一下对方就好了。 2、一个局域网下也ping不通:看看自己

    2024年02月04日
    浏览(36)
  • UNIX网络编程:socket & pthread_create()多线程 实现clients/server通信

    UNIX网络编程:socket fork()多进程 实现clients/server通信 随笔介绍了通过fork()多进程实现了服务器与多客户端通信。但除了多进程能实现之外,多线程也是一种实现方式。 重要的是,多进程和多线程是涉及操作系统层次。随笔不仅要利用pthread_create()实现多线程编程,也要理解线

    2024年02月06日
    浏览(39)
  • Linux网络编程:socket & pthread_create()多线程 实现clients/server通信

    UNIX网络编程:socket fork()多进程 实现clients/server通信 随笔介绍了通过fork()多进程实现了服务器与多客户端通信。但除了多进程能实现之外,多线程也是一种实现方式。 重要的是,多进程和多线程是涉及操作系统层次。随笔不仅要利用pthread_create()实现多线程编程,也要理解线

    2024年02月05日
    浏览(34)
  • 「网络编程」第二讲:网络编程socket套接字(三)_ 简单TCP网络通信程序的实现

    「前言」文章是关于网络编程的socket套接字方面的,上一篇是网络编程socket套接字(二),下面开始讲解!  「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 「枫叶先生有点文青病」「每篇一句」 I do not know where to go,but I have been on the road. 我不知

    2024年02月11日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包