前段时间和朋友一起做了一个类似于电驴、迅雷 + MSN工具的毛坯模型,基本上所有功能都是从socket通信级别向上实现。
整体架构为C/S架构,使用MFC实现。技术上都是很老的东西,此文主要介绍类似于 电驴 的这样一个软件的设计思路和部分代码框架。
我们实现的代码不是很优化,仅为设计思路的佐证。
我最初做这个小软件的想法是,方便一个小型网络中大家的资源共享和交流。
每个人都能共享出自己的一部分文件,当然这个可以通过WINDOWS的共享文件夹或者LINUX的SAMBA实现,不过假如在我并不知道共享源的情况下,就很难获得资源了。有人说,直接在WINDOWS的网上邻居里可以看到局域网上大家共享的资源,但是我发现可能由于各种网络设置的关系,在网上邻居里我经常看不到其他人共享的资源。
于是当时我用WINDOWS的几个API,(忘了具体是什么了,可以探测和遍历他人共享目录),写出来效果也很不好,第一很慢,第二还是收不全,第三不可控,其封装度太高,隐藏N多技术细节。
于是后来我想,还是基于socket,从底层做起。
在不知道源的情况下,我们如何探测、收集到各个源的共享资源呢?—— 答案很快浮出水面,弄一台服务器,大家都连接服务器,告诉它自己这儿的资源情况,然后大家统一从服务器查询网络上的共享资源,然后建立客户端的点对点连接传输文件。
程序的整体架构很简单,下面本文的主旨在于一步步的告诉大家在此软件实现中的一些要点。
1. 内部协议
我们的客户端需要与服务器端“交流”,就得有一套系统内部能被互相识别的语言,这样一套协议完全可以咱们自己设计。
我在实现中采用的UDP通信,每个UDP包 头一个字节为 指令字节,其后按照每个指令的格式跟接参数。例如我的“内部协议”部分代码:
/*********************************************/
// c->s 用户心跳
#define NS_UDP_LIVING 0x03
// c->s 用户更新共享信息
#define NS_UDP_UPDATE 0x04
// c->s 用户搜索
#define NS_UDP_SEARCH 0x05
// c->s 获取在线用户列表
#define NS_UDP_GET_ONLINE_USERS 0x06
// c->s 申请广播消息
#define NS_UDP_CLIENT_BORADCAST 0x07
// c->s 申请下载新版本客户端
#define NS_UDP_CLIENT_GETEXE 0x08
/*********************************************/
// s->c 用户登录成功
#define NS_UDP_LOGIN_SUCCESS 0x71
// s->c 传送搜索结果
#define NS_UDP_PUSHINFO 0x72
// s->c 传送在线用户列表
#define NS_UDP_PUSH_ONLINE_USERS 0x73
// s->c 广播消息
#define NS_UDP_BROADCAST_MESSAGE 0x74
// s->c 服务器重启,踢出所有用户
#define NS_UDP_SERVER_RESTART 0x75
// s->c 重新收集共享资料
#define NS_UDP_RECOLLECT_SHAREFILES 0x76
// s->c 踢出用户
#define NS_UDP_KICK 0x77
// s->c 客户端更新包
#define NS_UDP_CLIENT_UPDATE 0x78
/*********************************************/
// c->c 文件获取
#define NS_UDP_GETFILE 0x80
// c->c 文件获取许可
#define NS_UDP_ALLOW_GETFILE 0x81
// c->c 聊天消息
#define NS_UDP_MESSAGE 0x82
如果直接在网络上发送明文,则很容易被别人使用抓包工具抓取,稍加分析则可理解其中的内容,然后别人可以模拟写客户端或者程序来非法访问、攻击你的服务器端和别的客户端。所以这里应该要使用加密算法,在网路上传输加密数据。在我的“毛坯”程序中没有实现这一点,不过,这在互联网上发布的任何一款商用通信程序都是必须的。
2. TCP文件传输及传输群管理。
在一方申请下载的时候,另一方应该响应该请求,为它建立TCP连接。前者我们称TCP客户端、后者为TCP服务端。基于我们的“共享”的思想,每个客户端程序都可能作为TCP客户(下载资源)或者TCP服务器(提供资源下载),同时服务器端也可以作为TCP服务器(发布客户端自动升级包)。
那么我们总结核心思想就是,不管客户端还是服务器端,都应该有一个tcp listener,不断的监听网络上到来的TCP请求,每当过来一个请求时,与其建立连接,并且单独增开一个线程与其通信进行文件传输——我把这个机制叫做TCP文件传输群管理。
传输群管理应该包括以下几点
1. 侦听请求,建立连接;
2. 为连接增开线程;
3. 控制传输服务;
4. 结束传输,关闭线程。
下面给出我们传输群管理的核心部分代码:
大致说明一下,TCPServerManager为传输群管理,每次有连接单独启动一个TCPTaskManager作为TCP传输的容器类,负责管理一个TCP传输任务。
#ifndef NETSHARE_TCP_SERVER_MANAGER_H_
#define NETSHARE_TCP_SERVER_MANAGER_H_
#include "TCPServer.h"
#include "NetShareUDP.h"
#include <cpplib/MutexLock.h>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class TCPTaskManager;
class TCPServerManager;
//typedef void (TCPServerManager::*CALLBACK_DELETE)(int);
//发送文件数据结构
struct SendFileStructType
{
string filename;
string ip;
string dir;
DWORD offset;
TCPTaskManager* p_manager;
};
//TCP子任务管理器
class TCPTaskManager
{
public:
TCPTaskManager( SendFileStructType task )
: m_Speed( 0 )
, m_Task( task )
, m_MaxSpeed( 0 )
, m_IsFinish( FALSE )
, m_TaskHandler( 0 )
{
//this->Run();
m_pTCPServerInstance = new TCP_Server();
}
~TCPTaskManager(){}
//////////////////////////////////////////////////////////////////////////
void Speed( DWORD speed ) { m_Speed = speed; }
DWORD Speed(){ return m_Speed; }
void SetMaxSpeed( DWORD speed )
{
m_MaxSpeed = speed;
m_pTCPServerInstance->SetMaxSpeed( speed );
}
//发送完成后调用
//调用该方法并没有回收本类对应对象在TCPServerManager的m_pTasks中存在的实例,
//需要在TCPServerManager中再判断m_IsFinish的状态位加以移除。
void Finish()
{
CloseHandle( m_TaskHandler );
m_IsFinish = TRUE;
}
bool CheckFinish(){ return m_IsFinish; }
TCP_Server* GetTCPServerInstancePtr(){ return m_pTCPServerInstance; }
//////////////////////////////////////////////////////////////////////////
//TCP传送数据线程
static DWORD WINAPI TCPSendThreadProc(LPVOID lpParameter)
{
SendFileStructType* ptype = (SendFileStructType*)(lpParameter);
string ip = ptype->ip;
string filename = ptype->filename;
//TCP_Server ServerInstance;
TCP_Server* pServerInstance = ptype->p_manager->GetTCPServerInstancePtr();
pServerInstance->SetDir( ptype->dir );
pServerInstance->BindManager( ptype->p_manager );
pServerInstance->SendFile( ip,TCP_TRANCESPORT_PORT, filename, ptype->offset );
ptype->p_manager->Finish();
return 0;
}
void Run()
{
m_Task.p_manager = this;
m_TaskHandler = CreateThread( NULL, 0, TCPSendThreadProc, (LPVOID)&m_Task, 0, NULL );
}
protected:
DWORD m_Speed;//当前速度
DWORD m_MaxSpeed; //最大传输速度
SendFileStructType m_Task;
HANDLE m_TaskHandler;
bool m_IsFinish;
TCP_Server* m_pTCPServerInstance;
};
namespace
{
//检测一个任务是否已经完成
bool CompletedTask( TCPTaskManager* task )
{
return ( task->CheckFinish() );
}
}
//TCP文件传送服务器端管理类
class TCPServerManager
{
public:
TCPServerManager(){}
~TCPServerManager(){}
//添加文件传送任务
bool AddTask( SendFileStructType task );
//设置整体最大发送速度
void MaxSpeed( DWORD speed )
{
m_MaxSpeed = speed;
AdjustSpeed();
}
//删除编号为id的下载任务
void Delete( size_t id )
{
TaskMutex.Lock();
vector<TCPTaskManager*>::iterator iter = m_pTasks.begin();
for( size_t i = 0; i < id; i++ )
++iter;
delete *iter;
m_pTasks.erase( iter );
TaskMutex.Unlock();
AdjustSpeed();
}
//移除所有已完成的任务
void ClearCompleteTask()
{
try
{
TaskMutex.Lock();
vector<TCPTaskManager*>::iterator new_end = remove_if( m_pTasks.begin(), m_pTasks.end(), CompletedTask );
for( vector<TCPTaskManager*>::iterator iter = new_end; iter != m_pTasks.end(); ++iter )
delete *iter;
m_pTasks.erase( new_end, m_pTasks.end());
int k = m_pTasks.size();
TaskMutex.Unlock();
}
catch (...)
{
}
}
protected:
//获取当前整体发送速度
DWORD GetCurrTotalSpeed()
{
TaskMutex.Lock();
DWORD sum = 0;
for( vector<TCPTaskManager*>::iterator iter = m_pTasks.begin();
iter != m_pTasks.end();
++iter )
{
sum += (*iter)->Speed();
}
TaskMutex.Unlock();
return sum;
}
//获取当前传送任务数
int GetTaskNum()
{
ClearCompleteTask();
return m_pTasks.size();
}
//调整所有发送任务的发送速度
//暂时为平均分配
void AdjustSpeed()
{
if( m_MaxSpeed == 0 || GetTaskNum() == 0 )
return;
DWORD SingleMaxSpeed = m_MaxSpeed / GetTaskNum();
TaskMutex.Lock();
for( vector<TCPTaskManager*>::iterator iter = m_pTasks.begin();
iter != m_pTasks.end();
++iter )
{
(*iter)->SetMaxSpeed( SingleMaxSpeed );
}
TaskMutex.Unlock();
}
private:
DWORD m_MaxSpeed; //整体最大发送速度
vector<TCPTaskManager*> m_pTasks;
cpplib::resource::Mutex TaskMutex;//访问m_Task的互斥锁
};
#endif
未完待续。。。。
分享到:
相关推荐
总的来说,这个项目提供了一个基础的Socket文件传输模型,通过实践可以加深对Java网络编程的理解,为构建更复杂的应用,如聊天室、文件共享系统等打下坚实基础。对于开发者来说,熟练掌握Socket编程不仅可以增强解决...
在Linux系统中,实现基于Socket的多进程实时通信是一项重要的技术,它允许不同的进程间高效地交换数据。本文将详细介绍如何创建一个通信服务器(server)来作为中介,处理多个客户端(client)的连接和通信请求。 ...
本项目“用基于Socket做的类似资源管理器的文件共享”旨在创建一个简易的文件共享系统,其设计灵感来源于Windows资源管理器,使用户能够方便地进行文件的上传和下载,同时在操作过程中提供进度显示。 首先,Socket...
基于Socket的IPC消息平台为进程间通信提供了一个灵活、高效且易于集成的解决方案。通过线程池、消息队列和消息传输通道等关键技术的应用,不仅提高了系统的性能和吞吐量,还实现了真正的跨平台和跨语言特性,极大地...
总结来说,Linux下的多线程并发通信基于socket实现,结合TCP/IP协议,能够高效地处理多个客户端的并发请求。开发者需要理解套接字的概念、类型以及编程原理,同时掌握多线程编程技巧,包括线程安全、线程池等,以...
在本项目中,“QT实现的基于TCP Socket的共享白板”是一个利用QT库构建的、通过TCP Socket进行通信的多人协作工具。下面将详细介绍QT库、TCP Socket以及共享白板的相关知识点。 1. QT库: - QT库提供了一整套的C++...
基于SOCKET和多线程的应用程序间通信技术,不仅可以实现跨平台的数据通信,还能在保证数据准确性和完整性的同时,提高系统的响应速度和处理能力。通过对多线程的合理利用,可以有效地分配系统资源,优化数据处理流程...
本项目“基于Socket的多用户网络游戏”是一个典型的利用Socket实现的多人在线交互游戏,以井字游戏(Tic-Tac-Toe)为例,展示了如何通过网络连接让多个玩家在同一平台上进行实时对战。 首先,我们要理解什么是...
- **线程概念**:线程是进程中的一个执行流,同一进程内的多个线程可以并发执行,共享进程资源,提高程序并发性能。 - **创建线程**:在Linux中,可以使用`pthread_create()`函数创建新的线程,传入线程函数指针和...
Java基于Socket文件传输示例是一种常见的网络编程应用场景,主要用于实现两个网络节点间的文件共享和交换。Socket编程是Java网络通信的基础,它提供了低级别的、面向连接的、双向的数据传输通道。在这个示例中,我们...
综合以上,这个项目通过运用SOCKET实现网络通信,利用多线程提升并发处理能力,结合非阻塞模式确保服务的实时性,以及使用STL优化数据管理和算法执行,构建了一个高效且实用的远程算术运算系统。对于想要学习网络...
以上就是基于Socket的Android IPC通信的基本原理和实现步骤。通过这种方式,不同Android进程可以相互通信,实现复杂的功能,例如文件传输、实时消息推送等。但需要注意的是,Socket通信可能会消耗较多的系统资源,...
本文将深入探讨如何使用C#语言实现一个基于TCP/IP协议的多线程Socket聊天室。这个聊天室功能允许局域网内的多台计算机进行实时信息交互,虽然没有在广域网环境下测试,但在局域网内能有效工作。 首先,我们要理解...
总结来说,这个基于Socket的聊天工具项目涵盖了网络编程的核心概念,如TCP/IP协议、Socket接口、即时通讯实现、文件传输机制和屏幕截图共享。同时,由于提供了源代码,它对于开发者而言,是一个实践和学习网络编程的...
SOCKET编程中,创建SOCKET后需要绑定一个IP地址和端口号,端口号可以唯一标识网络中的一个进程,IP地址则用于标识不同计算机之间的通信。在基于Windows平台的SOCKET编程中,通常会使用Winsock(Windows Sockets)API...
随着互联网的普及,虚拟仪器的网络化趋势日益凸显,LabVIEW作为虚拟仪器的重要开发平台,提供了多种网络通信方式以满足远程测试、控制和资源共享的需求。本文主要探讨LabVIEW中的TCP、RDA、浏览器方式和DataSocket...
要实现Web服务器和Socket服务器之间的通信,你可以创建一个共享的数据结构,如全局变量或队列,两者都可以访问。例如,Web服务器接收到一个HTTP请求,处理后将数据放入队列,Socket服务器定期检查队列并发送数据给...
在IT行业中,网络通信是计算机科学的一个重要领域,特别是在分布式系统和互联网应用中。Socket编程是一种基础且核心的技术,它提供了进程间通信(IPC)的能力,使得运行在不同机器上的程序能够相互通信。本篇将详细...
【标题】: "基于socket的聊天工具(含源码)" 是一个网络编程项目,它使用了Socket编程技术来实现客户端和服务器之间的实时通信。Socket是网络编程中的基本接口,允许两个程序通过网络进行数据交换,通常用于构建聊天...
本项目“基于Python 洪泛 技术实现了一个资源共享系统”旨在利用这种技术构建一个用户友好的文件共享和资源下载平台。在这个系统中,用户可以上传文件并让其他用户下载,实现了资源的广泛传播和利用。 首先,让我们...