Winsock程序设计入门(3)修订版-多线程TCP服务器和客户端

Beginning Winsock Programming - Multithreaded TCP server with client
开始学Winsock编程-多线程TCP服务器和客户端

原作者:Nishant Sivakumar
原文链接:http://www.codeproject.com/KB/IP/winsockintro03.aspx
翻译:DKink|棼紫

前面我们介绍了接受一个连接的TCP服务器和HTTP文件下载程序。很明显一个服务器必须处理多个客户端同时连接。前面写的程序就不行了。在这篇文章里我们写一个多线程TCP服务器。另外我们将自定义TCP聊天协议,虽然是很简陋的。我们还写一个客户端连接这个服务器和使用聊天协议。通过同时运行服务器和多个客户端来测试是否真的实现多个连接。服务器简单的发送回应文件到客户端,客户端将保存它到本地机器。

 

这里所使用的是古老的一个线程处理一个连接的方法。还有其他更有效率的方法比如说完成端口(IO completion ports)。这种方法满足一般需求,除非是不规则大量连接的。

 

*编写多线程服务器
你如果读了前面的文章就会明白怎么建立一个TCP服务器。如果你没有读过,最好先看前面的文章。main()函数并没有多大的变化。开始服务器线程,并且使用_getch()使按下ESC键时关闭关闭服务器socket和退出。

下面看服务器线程函数的编写。listen()部分没有太大的变化,accept()部分有少许改动。

实质上很简单,我们接受一个连接并把客户socket传给一个新启动的线程。在这个线程里处理客户的事务,这样我们就可以不断接受并处理新的连接。是不是没有你想象的那么困难。

*我们自定义的通讯协议

现在让我们自定义自己的TCP聊天协议。我们显然需要一个指令来关闭会话,会采用"QUIT"吗?这似乎是很好的选则。我们并不希望每个人都能下载文件。添加一个"AUTH"指令附带一个参数作为密码。密码正确则进入特许状态。"QUIT"和"AUTH"可以工作在非特许状态。"FILE"指令被用于下载文件只允许运行在特许状态。这样我们就有了三条指令。两条可在任何状态下使用,一条只在特权状态下使用。

QUIT  :- 这个将关闭连接。
AUTH [password]  :- 这个将记录用户进入特权模式。
FILE [filename with full path] :- 获取文件(只能工作在特权模式)

想象一下我们的协议,用#标记成功的提示,用!标记错误的提示。在我们写实现代码前先预览一下我们会话时的样子:
//================================================
Trying 192.168.1.44...
Connected to 192.168.1.44.
Escape character is '^]'.
#Server Ready.
file c:/config.sys
!You are not logged in.
auth yellow
!Bad password.
auth passwd
#You are logged in.
file c:/config.sys
DEVICE=C:/WINDOWS/HIMEM.SYS
DEVICE=C:/WINDOWS/EMM386.EXE
#File c:/config.sys sent successfully.
file c:/setup.log
[InstallShield Silent]
Version=v6.00.000
File=Log File

[ResponseResult]
ResultCode=0

[Application]
Name=Intel Ultra ATA Storage Driver
Version=6.03.007
Company=Intel
Lang=0009
#File c:/setup.log sent successfully.
file d:/g5.doc
!File d:/g5.doc could not be opened.
quit
Connection closed by foreign host.

//====================================
你可以看到一个用户登陆,他浏览了一些文件。我这里只展示了文本文件,但是他也可以很好的处理二进制文件。在我们稍后写的客户端程序我们也这样做。现在展示处理客户会话协议的线程代码。

我将简述这段代码的执行。我们首先发送一个服务器会话,大多数TCP都差不多这样。接着不断循环并接

受指令。我们使用自己的ParseCmd()函数解析传入的命令为两个CString对象,一个包含命令另外一个包

含参数。如果ParseCmd()返回true这意味着有一个未知的命令传入,这时我们返回一个错误提示。
如果命令是"QUIT"我们退出While循环并结束客户socket和退出线程。我们还需要一个boolean标志为认证

系统服务,true时为客户通过认证。用户没通过认证而获取文件会被告知未登录。这里我们硬编

码"passwd"为我们的密码,但是在实际的应用中用户名和口令会被保存在数据库或配置文件中。
使用AUTH命令用户可以登陆。我们对比口令,如果符合发送已登录通知并设置登陆标志为true,否则发送

一个登录失败提示。验证通过后就可以检索文件。我们使用一个叫SendFile的函数通过TCP连接发送文件

。我希望这些简述是清晰的。
下面让我们看一下ParseCmd()函数。

正如你所看到的这个函数是简单易懂的。他识别命令返回true,其他状况返回false。下面我们看SendFile()的实现

这仍然是个简单函数。成功发送文件返回true,未找到文件返回false。有点困惑的是我在ParseCmd()函

数中使用true表达发生错误,而在这里使用false表达发生错误。我想我有很长时间没有写过标准代码了

。我希望各位能原谅我这个严重的个人错误。
到这里我们已经写好了使用自定义协议的TCP服务器。接着要继续写一个小的客户端程序来连接这个服务

器并从服务器上下载文件。
*定制客户端
我不想继续描述源代码。你可以参考上一篇文章《simple TCP client》。只有一点需要注意,不要使用

一些字符串处理函数比如strcpy()和strchr()对recv()返回的缓冲区操作。这些字节缓冲区可能不是以

null结尾的,使用strcpy()类函数会毁坏你的程序。你可以打开源代码查看,发现我并没有使用这类字符

处理函数。
这里演示如何使用客户端。我在客户端里硬编码了服务器地址为127.0.0.1。如果你不在同一台机器上运

行服务器和客户端你需要更改这个地方。在你启动客户端前确保服务器端已经正常运行。
//==============================================
E:/work/MTSClient/Debug>mtsclient
Usage :- mtsclient [file1] [file2] [file3] ....

E:/work/MTSClient/Debug>mtsclient c:/cu.gif c:/cp.gif c:/g.gif c:/ddd
File c:/cu.gif not found on server
cp.gif has been saved.
g.gif has been saved.
File c:/ddd not found on server

E:/work/MTSClient/Debug>
//=====================================
*结尾
这可能是我介绍使用winSock的TCP编程文章的最后一篇。现在你已经能够编写基本的TCP客户端和服务器(

包括多线程版本的)。我建议你去尝试写一个简单的程序连接POP服务器,登陆并检查你是否有邮件。或编

写一个使用SMTP会话发送邮件的程序。为了检查你的服务器编程技巧,你可能会写一个简单的HTTP服务器

,或是自定义协议的服务器,或是其他你想到的、感兴趣的东西。
*许可
这篇文章没有详细的许可内容,有问题请联系作者。

*翻译者的牢骚

唉,我这种CET4考340分的人给大家翻译文章,凑合看吧。源代码请到原文处下载,这篇文章的源代码VC6的工程没问题,你要是有问题也可以问我。如果有谁在VS2008下不能编译可以告诉我,我会提供配好的工程文件。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值