很多程序有这样的功能,双击某个图片可以打开源文件,右键菜单中的Show in Finder功能,Cocoa中对这块支持较好,有现成的方法:
[[NSWorkspace sharedWorkspace] openFile:fileName];
[[NSWorkspace sharedWorkspace] selectFile:fileName inFileViewerRootedAtPath:path]; // 如果只打开目录不需要选中具体文件,fileName可为nil。
下载原理: 网上介绍很多,就是按照Http协议,使用Socket连接并发送请求头给Http服务器,若服务器正确响应,返回请求文件数据,接收并写文件保存.至于Http协议的请求头及响应头的格式,这里不再赘述,请Google之.
实现: 为此,我封装了一个HttpDownload类.先上代码...(基于WinSocket,移植时请注意部分函数)
(HttpDownload.h)
2 #define HTTP_DOWNLOAD_H
3
4 #include <cstdio>
5 #include <string>
6 #include <winsock2.h>
7
8 class HttpDownload {
9 public:
10 HttpDownload(const char* hostAddr, const int port,
11 const char* getPath, const char* saveFileName);
12 ~HttpDownload();
13 bool start();
14 void cancel();
15 void getPos(ULONGLONG& totalSize, ULONGLONG& downloadSize);
16 protected:
17 bool initSocket(); //初始化Socket
18 bool sendRequest(); //发送请求头
19 bool receiveData(); //接收数据
20 bool closeTransfer(); //关闭传输
21 private:
22 std::string m_hostAddr; //目标主机IP
23 int m_port; //HTTP端口号
24 std::string m_getPath; //目标文件相对路径
25 std::string m_saveFileName; //保存文件路径
26 SOCKET m_sock; //Socket
27 FILE* m_fp; //保存文件指针
28 ULONGLONG m_fileTotalSize; //目标文件总大小
29 ULONGLONG m_receivedDataSize; //已接收数据大小
30 bool m_cancelFlag; //取消下载标记
31 };
32
33 #endif //HTTP_DOWNLOAD_H
(HttpDownload.cpp)
2
3 #define BUFFER_SIZE 1024
4
5 HttpDownload::HttpDownload(const char* hostAddr, const int port, const char* getPath, const char* saveFileName)
6 {
7 m_hostAddr = hostAddr;
8 m_port = port;
9 m_getPath = getPath;
10 m_saveFileName = saveFileName;
11 m_sock = 0;
12 m_fp = NULL;
13 m_fileTotalSize = 1; //没给0,因为分母
14 m_receivedDataSize = 0;
15 m_cancelFlag = false;
16 }
17
18 HttpDownload::~HttpDownload()
19 {
20
21 }
22
23 bool HttpDownload::initSocket()
24 {
25 m_sock = socket(AF_INET, SOCK_STREAM, 0);
26 if (m_sock < 0)
27 return false;
28
29 //设置Socket为非阻塞模式
30 unsigned long mode = 1;
31 if (ioctlsocket(m_sock, FIONBIO, &mode) < 0)
32 return
大型网络游戏服务器的逻辑大多采用单线程设计,典型的就是一个线程处理一个区域(地图),跨区域通过跳转实现,这样,不同区域的对象在逻辑上是不发生交互的。
这样在一台服务器上开启N个线程就可以处理N个区域。但一个线程处理一个区域毕竟有其瓶颈,如果一个区域内挤进了过多的玩家就会导致为那个区域服务的线程
不负重和,表现就是那个区域中的玩家发现操作响应变得不及时.
最近一段时间在思考如何能并行的利用多进程多机器为同一片区域服务,这样可以通过多开几个进程提升单区域的承载量。一种方式是类似bigworld全分布式设计,
同一区域中的对象可以分布在N个进程/机器中。以一个玩家为例,在一个进程中其是主动对象,所有对这个玩家对象的属性操作都必须在主动对象上执行.在其它进
程中的对象要跟这个玩家交互,例如战斗,所以这个玩家对象必须在其主动对象所在进程以外有副本对象,这样在另外一个进程中的对象可以根据这个玩家的副本
对象的属性值计算战斗伤害,抵抗等等,然后将属性变更请求发回给玩家所在的主动对象,执行实际的属性变更.以这种方式,主动对象的属性变更必须通知到所有
的副本对象。由于主动对象的属性变更后需要通知所有的副本对象,当这个区域中对象数量变得很大时,属性变更带来的通信量将会非常大.
现在换个思路,结合多线程和多进程,在一个进程中启动多个线程,主动对象位于一个线程中,属性数据在多个线程中可见,只有主动对象所在线程能修改那个对象
的属性,其它线程只能读取,这样,同一个进程中的多个线程就免除了属性同步的需要.
对于32/64位的基本属性,其读写本身就是原子的,所以可以安全的实现一个线程写,N个线程读.但对于一些结构型的属性,最典型的就是坐标,由x,y,z三个分量
构成,对其读/写都不是原子的.为了实现原子的读写坐标,最简单的做法就是在SetPos/GetPos中加锁。但再想一想,我们要读取的只是一份完整,正确的坐标数据,
却可以容忍其不一定是最新的数据。所以,下面实现了一个无锁的算法实现安全的对结构体的1写N读。
{
volatile int version;
volatile int x;
volatile int y;
volatile int z;
};
//#define _USE_MTX_
struct point_container
{
uint32_t g_version;
struct point array[2];
int32_t index;
mutex_t mtx;
#ifdef _USE_MTX_
struct point p;
#else
volatile struct point *ptr;
#endif
};
{
struct point ret;
while(1)
{
volatile struct point *ptr_p = pc->ptr;
int save_version = ptr_p->version;
if(ptr_p == pc->ptr && save_version == ptr_p->version)
{
ret.x = ptr_p->x;
ret.y = ptr_p->y;
ret.z = ptr_p->z;
__asm__ volatile("" : : : "memory");
if(ptr_p == pc->ptr && save_version == ptr_p->version)
{
if(ret.x != ret.y || ret.x != ret.z || ret.y != ret.z)
{
printf("%d,%d,%d,%u\n",ret.x,ret.y,ret.z,save_version);
assert(0);
}
break;
}
ATOMIC_INCREASE(&miss_count);
}
else
ATOMIC_INCREASE(&miss_count);
}
ATOMIC_INCREASE(&get_count);
return ret;
}
void SetPoint(struct point_container *pc,struct point p)
{
struct point *new_p = &pc->array[pc->index];
pc->index = (pc->index + 1)%2;
new_p->x = p.x;
new_p->y = p.y;
new_p->z = p.z;
__asm__ volatile("" : : : "memory");
new_p->version = ++pc->g_version;
__asm__ volatile("" : : : "memory");
pc->ptr = new_p;
ATOMIC_INCREASE(&set_count);
}
其中point_container用于存放实际的point数据,GetPoint/SetPoint分别用于从point_container中读取和写入point数据.
{
int idx = 0;
int pos = 0;
while(1)
{
struct point p;
++pos;
p.x = p.y = p.z = pos+1;
SetPoint(&g_points[idx],p);
idx = (idx + 1)%1;
}
}
void *GetRoutine(void *arg)
{
int idx = 0;
while(1)
{