支持网络对战的五子棋程序

五子棋交流


#1 支持网络对战的五子棋程序 作者:有志青年 发表时间:2007-3-10 20:32:40


过年前几天无聊时写了这个程序,顺便把API和网络编程练习了一下,单机部分不到一天就写出来了,网络部分却麻烦,要维持远程双方两个进程的同步似乎是非常麻烦的事情,双方在连接时的各种操作都有可能导致连接状态的改变,对弈时假如双方维护的棋盘副本或者其它对弈信息不一致,都会导致双方都阻塞从而使对弈无法进行下去,或者双方的行棋信息完全不同。整整耗了我一个星期,总算可以比较正常的运行了,可是还是感觉不大稳定。
设计及构建时我主要的问题如下:
进程同步和线程同步
    通常认为每个进程的内存都是独享的,而单个进程中多个线程的内存是共享的,照此理解,既然进程的内存是独享的,进程之间又怎么能共享内存数据?若不能共享内存数据,则怎样进行进程同步?进程之间可以通过磁盘文件和外设共享数据,但这样性能代价太高,显然不适于进程同步。还有一种可能的方案是通过消息传递机制,似乎很麻烦。
    在我看来,一般所说的进程同步更像是线程同步,线程之间共享内存变量,多个线程对共享变量的访问显然需要同步,而这一机制与采用的策略与我们所学的进程同步似乎没什么区别。
    而不同进程之间如何进行同步?只能采用消息传递机制吗?如不同主机上的两个进程若要同步,是不是只能各自维护一份本地数据,然后通过网络传送消息来保持这些数据的一致性?这似乎是一个非常棘手的问题,因为网络的通信质量通常不稳定,而每个进程内部,各线程之间还常常发生上下文切换,这就需要同时处理每个进程内部各线程的同步,以及不同进程之间的线程的同步。
    我在设计一个网络程序时,发现接收数据必须单开一个线程,并时刻处于监听状态,这样主线程才能去做其他事,否则整个程序的执行将被阻塞,或者另一方无法发送成功。但这样一来,假如接收方整个程序的继续执行需要使用接收到的数据,而发送方进程退出或被意外中止,则接收将失败,如此一来接收方将处于无限等待状态!一种可能的解决方案是发送方在退出之前发送一条退出消息,接收方收到之后就知道发送方已退出。我采用这一方案后,基本上解决了这一问题,但问题有时候还是会出现,个人感觉是线程多了之后同步没做好所导致(我为每个进程开了4个线程,分别是主线程,后台工作线程,发送线程和接收线程)。有没有更好的解决方案?

关于该程序的一些说明如下:
该工程所需的库文件:
WS2_32.lib           winsock2的库文件

以下二者选一即可:
LIBCMT.LIB           多线程的支持库(静态库,生成exe之后不再需要dll)
MSVCRT.LIB           多线程的支持库(动态库,需要MSVCRT.DLL)

在建立多线程的Windows程序时,需要在「Project Settings」对话框中做一些修改。选择「C/C++」页面标签,然后在「Category」下拉式清单方块中选择「Code Generation」。在「Use Run-Time Library」下拉式清单方块中,可以看到用于「Release」设定的「Single-Threaded」和用于Debug设定的「Debug Single-Threaded」。将这些分别改为「Multithreaded」和「Debug Multithreaded」。这将把编译器旗标改为/MT,它是编译器在编译多线程的应用程序所需要的。具体地说,编译器将在.OBJ文件中插入LIBCMT.LIB文件名,而不是LIBC.LIB。连结程序使用这个名称与执行期链接库函数连结。

LIBC.LIB和LIBCMT.LIB文件包含C语言链接库函数,有些C语言链接库函数包含静态数据。例如,由于strtok函数可能被连续地多次呼叫,所以它在静态内存中储存了一个指标。在多线程程序中,每个线程必须在strtok函数中有它自己的静态指针。因此,这个函数的多线程版本稍微不同于单线程的strtok函数。

联网对弈时,各方均启用3个子线程,每个子线程控制一个socket,一个用于发送聊天及辅助信息,一个用于接收聊天及辅助信息,一个传输下棋信息。其中下棋的socket采用半双工传输方式轮流收发信息,接受的socket则时刻监听,而发送的socket在有信息发送时发送。

可惜sina的blog不能上传文件,我不能将源文件和可执行文件打包上传上去。谁想要的可以给我发邮件:
dts7486@sina.com
。我直接发给他。