资源描述
海南大学信息学院信息安全系专业课程
《安全扫描》课程设计报告
姓 名:
学 号:
学 院: 信息科学技术学院
成 绩:
任课教师: 顾 剑
二〇一三年十二月五日
目 录
摘 要 ----------------------------------------------------------------1
1.引言 -----------------------------------------------------------------1
1.1开发背景 -------------------------------------------------------1
1.2 设计题目及要求-----------------------------------------------1
2.程序的编译与开发 -----------------------------------------------2
2.1 开发目的 -------------------------------------------------------2
2.2 开发环境及工具------------------------------------------------2
2.3 开发过程---------------------------------------------------------2
3.基本思路及所涉及的相关理论 ---------------------------------2
3.1基本思路----------------------------------------------------------2
3.2相关理论----------------------------------------------------------2
3.2.1协议介绍 -----------------------------------------------------2
3.2.2 TCP实现流程------------------------------------------------3
3.2.3 UDP实现流程------------------------------------------------5
3.2.4 Windows Socket 套接字编程原理------------------------------6
4.实验过程--------------------------------------------------------------10
5、个人感想与感悟 -------------------------------------------------- 23
附录(程序代码部分)------------------------------------------------23
附录一:(基于TCP通信的客户端与服务器)----------------------23
附录二:(基于UDP通信的客户端与服务器)----------------------29
附录三:(基于 TCP/UDP 的网络安全扫描) ----------------------38
摘 要
计算机信息网络的发展加速了信息化时代的进程,但是随着社会网络化程度的增加,对计算机网络的依赖也越来越大,网络安全问题也日益明显。端口扫描技术室发现安全问题的重要手段之一。
当前进行网络端口扫描的主要技术有:基于ARP、ICMP、TCP(包括TCP connect扫描、TCP SYN扫描、TCP ACK 扫描、TCP FIN扫描等)、UDP 网络协议的网络活动端口扫描。
(1)、利用ARP协议获取活动主机的MAC地址,当获取的不为“00-00-00-00-00-00”时,则认为当前主机可达,是活动的主机;
(2)、利用ICMP协议,使用系统自带的PING程序,当能PING 通目标主机时,认为是活动主机(能扫描到活动的端口);
(3)、基于TCP的链接状态当判断链接成功认为主机可到达(并能扫描到相应的端口);
(4)、基于UDP 的不可靠传输,我们可以通过套接字编程给目标主机发送消息,能够得到返回消息,则认为主机可到达(相应扫描到端口)。
根据以上方法,我们均能扫描到开放的端口,因此,我们同样可以做到对自己电脑的自纠自查,对自己的主机实施相应的网络安全保护。
关键字:TCP连接 套接字 TCP/UDP端口扫描.
客户端、服务器及网络安全扫描的实现
1.引言
1.1开发背景
端口扫描,顾名思义,就是对目标主机的端口依次进行连接,对于能进行数据通信的,则认为是”开”状态,否则认为是”关”状态。由于绝大部分公用服务于端口有对应关系,因此通过端口的”开”与”关”状态,可以初步判断对方是否提供相应的服务,为下一步的操作提供参考。
端口是一个传输层的概念,因此端口扫描也仅限于在传输层上进行,传输层一般将协议分为TCP协议和UDP协议,所以端口扫描也根据扫描所采用的类型分为TCP端口扫描、UDP端口扫描两大类。
端口扫描与其说是一种攻击方法,不如说是一种检测方法,因为通过端口扫描,即使是知道对方哪些端口是开的,也不意味着对方就一定提供了这些端口对应的服务,更谈不上能查出什么漏洞。但黑客正是用端口扫描预测一台主机上都提供了哪些服务,如果所提供的这些服务存在漏洞,黑客就会利用这些漏洞对系统进行攻击。而事实上即使没有什么漏洞可找,仅就扫描所得的信息,就已经给黑客提供大量的重要信息,因此端口扫描往往作为黑客攻击的第一步。所以,对于任何一个拥有电脑的用户完全有必要对端口进行详细地了解,对于没有实质性作用的端口要关闭,对于必须开放的端口则尽可能地安装其漏洞补丁程序。
1.2 设计题目及要求
(1)、 至少建立TCP/UDP两台服务器
服务器端口和服务必须有公开和保密(后门)两类。
(2)、完成TCP/UDP协议客户端扫描程序
可以扫描出公开和保密的全部端口号,确定全部公开的服务,甚少可以确定一种保密的服务。
(3)、可以扫描顾剑老师上课的服务器210.37.47.194,检查其安全情况。
(4)、可以扫描 服务器,检查其安全情况。
(5)、同学之间可以互相扫描各自的服务器,检查其服务情况。
(6)、不可扫描其他境内服务器。
(7)、写出完整的试验报告,并尝试给出一些防范和修改建议。
2.程序的编译与开发
2.1 开发目的
1.了解和掌握TCP/IP协议的基本原理(TCP通信、UDP通信);
2.了解网络环境下的程序设计步骤和过程;
3.掌握Winsock提供函数的功能和用法。
2.2 开发环境及工具
测试平台:Windows XP Professional
使用软件:Microsoft Visual C++ 6.0
开发语言:C语言
2.3 开发过程
根据题目的要求,结合相应的算法理论及相关的基础知识,在Microsoft Visual C++ 6.0的平台下进行开发。具体过程参见下述的算法理论部分和程序流程步骤的分析。
3.基本思路及所涉及的相关理论
3.1基本思路
根据题目要求,逐步解析题目含义。实际上,该题目包含三个主要程序:①基于TCP客户端和服务器间的通信;②基于UDP客户端与服务器的通信;③基于TCP和UDP的网络活动端口扫描。由所学知识可知:TCP属于面向连接型协议(可靠传输,通过三次握手连接完成),UDP属于不可靠传输。在Windows平台上,需要通过Winsock套接字编程来实现。
3.2相关理论
3.2.1协议介绍
(1)TCP
TCP/IP(Transmission Control Protocol/Internet Protocol) 即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WAN)设计的。它是由ARPANET网的研究机构发展起来的。
有时我们将TCP/IP描述为互联网协议集"InternetProtocolSuite",TCP和IP是其中的两个协议(后面将会介绍)。由于TCP和IP是大家熟悉的协议,以至于用TCP/IP或IP/TCP这个词代替了整个协议集。这尽管有点奇怪,但没有必要去争论这个习惯。例如,有时我们讨论NFS是基于TCP/IP时,尽管它根本没用到TCP(只用到IP和另一种交互式协议UDP,而不是TCP)。
TCP/IP的标准在一系列称为RFC的文档中公布。文档由技术专家、特别工作组、或RFC编辑修订。公布一个文档时,该文档被赋予一个RFC编号,如RFC959(FTP的说明文档)、RFC793(TCP的说明文档)、RFC791(IP的说明文档)等。最初的RFC一直保留而从来不会被更新,如果修改了该文档,则该文档又以一个新号码公布。因此,重要的是要确认你拥有了关于某个专题的最新RFC文档。通常在RFC的开头部分,有相关RFC的更新(update)、修改(errata)、作废(obsolete)信息,提示读者信息的时效性。详情请阅读网站RFC-editor[1]。
(2)UCP
UDP协议的全称是用户数据包协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天UDP仍然不失为一项非常实用和可行的网络传输层协议。
与所熟知的TCP(传输控制协议)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。
UDP协议的主要作用是将网络数据流量压缩成数据包的形式。一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。
3.2.2 TCP实现流程:
图 3.2.1-1面向连接(TCP)的socket工作流程
图3.2.1-2 TCP正常连接过程 图3.2.1-3 TCP正常终止连接过程
图 3.2.1-4 TCP 连接过程
3.2.3 UDP实现流程:
图 3.2.2-1 UDP工作过程
图 3.2.2-2 UDP扫描过程
3.2.4 Windows Socket 套接字编程原理
一、客户机/服务器模式
在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Server model)。该模式的建立基于以下两点:1、非对等作用;2、通信完全是异步的。客户机/服务器模式在操作过程中采取的是主动请示方式:
首先服务器方要先启动,并根据请示提供相应服务:(过程如下)
1、打开一个通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求。
2、等待客户请求到达该端口。
3、接收到重复服务请求,处理该请求并发送应答信号。
4、返回第二步,等待另一客户请求
5、关闭服务器。
客户方:
1、打开一个通信通道,并连接到服务器所在主机的特定端口。
2、向服务器发送服务请求报文,等待并接收应答;继续提出请求……
3、请求结束后关闭通信通道并终止
二、套接字
1. 套接字地址结构
(1)、sockaddr结构:
struct sockaddr
{
u_short sa_family; /* address family */
char sa_data[14]; /* up to 14 bytes of direct address */
};
sa_family为网络地址类型,一般为AF_INET,表示该socket在Internet域中进行通信,该地址结构随选择的协议的不同而变化,因此一般情况下另一个与该地址结构大小相同的sockaddr_in结构更为常用,sockaddr_in结构用来标识TCP/IP协议下的地址。换句话说,这个结构是通用socket地址结构,而下面的sockaddr_in是专门针对Internet域的socket地址结构。
(2)、sockaddr_in结构
struct sockaddr_in
{
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
sin _family为网络地址类型,必须设定为AF_INET。sin_port为服务端口,注意不要使用已固定的服务端口,如HTTP的端口80等。如果端口设置为0,则系统会自动分配一个唯一端口。sin_addr为一个unsigned long的IP地址。sin_zero为填充字段,纯粹用来保证结构的大小。
2.套接字的使用步骤
(1)、启动Winsock:对Winsock DLL进行初始化,协商Winsock的版本支持并分配必要的资源。(服务器端和客户端)。
(2)、创建套接字:(服务器端和客户端)
SOCKET socket( int af, int type, int protocol );
①、af为网络地址类型,一般为AF_INET,表示在Internet域中使用。
②、type为套接字类型,前面已经介绍了。
③、protocol为指定网络协议,一般为IPPROTO_IP。
(3)、套接字的绑定:将本地地址绑定到所创建的套接字上。(服务器端和客户端)
int bind( SOCKET s, const struct sockaddr FAR * name, int namelen )
①、s为已经创建的套接字。
②、name为socket地址结构,为sockaddr结构,如前面讨论的,我们一般使用sockaddr_in结构,在使用再强制转换为sockaddr结构。
③、namelen为地址结构的长度。
(4)、套接字的监听:(服务器端)
int listen(SOCKET s, int backlog )
①、s为一个已绑定但未联接的套接字。
②、backlog为指定正在等待联接的最大队列长度,这个参数非常重要,因为服务器一般可以提供多个连接。
(5)、套接字等待连接:(服务器端)
SOCKET accept( SOCKET s, struct sockaddr FAR * addr, int FAR * addrlen )
①、s为处于监听模式的套接字。
②、sockaddr为接收成功后返回客户端的网络地址。
③、addrlen为网络地址的长度。
(6)、套接字的连接:将两个套接字连结起来准备通信。(客户端)
int connect(SOCKET s, const struct sockaddr FAR * name, int namelen )
①、s为欲连结的已创建的套接字。
②、name为欲连结的socket地址。
③、namelen为socket地址的结构的长度。
(7)、套接字发送数据:(服务器端和客户端)
int send(SOCKET s, const char FAR * buf, int len, int flags )
①、s为服务器端监听的套接字。
②、buf为欲发送数据缓冲区的指针。
③、len为发送数据缓冲区的长度。
④、flags为数据发送标记。
⑤、返回值为发送数据的字符数。
(8)、套接字的数据接收:(客户端)
int recv( SOCKET s, char FAR * buf, int len, int flags )
①、s为准备接收数据的套接字。
②、buf为准备接收数据的缓冲区。
③、len为准备接收数据缓冲区的大小。
④、flags为数据接收标记。
⑤、返回值为接收的数据的字符数。
(9)、中断套接字连接:通知服务器端或客户端停止接收和发送数据。(服务器端和客户端)
int shutdown(SOCKET s, int how)
①、s为欲中断连接的套接字。
②、How为描述禁止哪些操作,取值为:SD_RECEIVE、SD_SEND、SD_BOTH。
(10)、关闭套接字:释放所占有的资源。(服务器端和客户端)
int closesocket( SOCKET s )
①、s为欲关闭的套接字
三、典型过程图
1. 面向连接的套接字的系统调用时序图
图 3.2.3-1
2.无连接协议的套接字调用时序图
图 3.2.3-2
4、实验过程
(1)、至少建立TCP/UDP两台服务器
服务器端口和服务必须有公开和保密(后门)两类。
一、TCP服务器
①、公开服务:在与客户端进行连接时,能够接收客户端发送过来的消息。并返回相同的消息以响应客户端,同时日志文件将会记录这一切:(如图4-1所示)
图 4-1 公开服务接收信息
②、保密服务:当客户端发送停机密码时,服务器会自动关机,不对任何客户端提供服务:(图4-2、图4-3)
图 4-2(收到停机密码的服务器)
图 4-3(发送了停机密码的客户端)
二、UCP服务器
①、公开服务:能够接收客户端发送过来的消息,并响应客户端,同时日志文件将会记录这一切:(如图4-4所示)
图4-4公开服务接收信息
图 4-5 UDP客户端界面
4-6 发送了消息的UDP客户端界面
图 4-7 服务器开启了日志功能
②、保密服务:在客户端发送了停机密码后,可以控制服务器关机,但同时也会被服务器记录在案。以便今后管理员对攻击事件的追踪。
图 4-8 服务器开启日志功能
(2)、完成TCP/UDP协议客户端扫描程序
可以扫描出公开和保密的全部端口号,确定全部公开的服务,甚少可以确定一种保密的服务。
①、扫描本机
1:查看哪些端口是开放的。
图 4-9查看本机端口的开放情况
2:采用传统单线程扫描熟知端口。
图 4-10 传统顺序扫描的结果截图
3:日志功能
图 4-11 日志记录
5:采用多线程扫描熟知端口
图 4-12 多线程扫描的结果截图
6:日志功能
图 4-13 日志功能
由以上截图对比可知,单线程扫描的速度慢,而多线程扫描则实现了高并发,扫描速度得到了大幅度的提升。但多线程扫描的难题是如何实现高并发却不会出现错误。
因此,本人在扫描器中设定了两种模式,当扫描的端口范围较小时,建议使用单线程模式,这样可以避免多线程扫描端口范围较小时产生的错误,虽然单线程是顺序扫描而且一般服务器都有日志功能,但是扫描的范围较小时,比扫描端口范围大的更不容易被服务器察觉。当扫描端口范围较大时,建议采用多线程模式,首先是因为它的扫描速度比单线程模式快得多,每多创建一个线程扫描速度单线程快一倍,但线程并不是越多就越好,在这里我只创建了50个线程,扫描速度大约是原来单线程的50倍。其次,它所扫描的端口具有一定的随机性,如果采用传统的单线程模式顺序扫描并且扫描的端口范围大时,不仅扫描时间长,而且是顺序扫描,这样做是不明智的!
(3)、可以扫描顾剑老师上课的服务器210.37.47.194,检查其安全情况。
第一步:查看主机是否存活。Ping 210.37.47.194
图 4-9 查看主机是否存活
第二步:扫描主机的熟知端口号(0~1024)。
图 4-10扫描主机的熟知端口号(0~1024)
图 4-11 日志功能
第三步:扫描主机的登记端口号(1025~49151)。
图 4-12扫描主机的登记端口号(1025~49151)
图 4-13 日志功能记录
综上,服务器210.37.47.194提供了ftp服务和telnet服务。首先,telnet服务器容易遭受到拒绝服务攻击,另外telnet服务的开放使得为不合法用户开启了远程登录,并控制服务器,最后留下入侵后门。
(4)、可以扫描 服务器,检查其安全情况。
第一步:登陆网站,查看网址是否有效。
图 4-14登陆网站,查看网址是否有效
第二步:ping 域名以获得IP地址。
图4-15 ping 域名以获得IP地址
第三步:扫描服务器的熟知端口(0~1024)
图 4-16扫描服务器的熟知端口(0~1024)
给出一些防范和修改建议:linux的111端口可能存在安全隐患。建议关闭此端口。111端口是SUN公司的RPC(Remote Procedure Call,远程过程调用)服务所开放的端口,主要用于分布式系统中不同计算机的内部进程通信,RPC在多种网络服务中都是很重要的组件。常见的RPC服务有rpc.mountd、NFS、rpc.statd、rpc.csmd、rpc.ttybd、amd等等。在Microsoft的Windows中,同样也有RPC服务。如果可以不使用RPC服务的话,建议关闭此端口。
第四步:查看该扫描记录是否已存于日志文件中
图 4-17 日志功能
第五步:扫描服务器的登记端口号(1025~49151)
图 4-18扫描服务器的登记端口号(1025~49151)
第六步:查看日志
图 4-19 查看日志
分析:45457端口开放,可能是某黑客留下的一个后门,建议系统管理员尽快关闭此端口。否则将会被某些黑客利用。
5、个人感想与感悟
通过本次课程设计使我更为深刻地认识到了编程的重要性,虽然老师让我们写的代码很多,但其实许多程序都是在老师的程序基础上修改的,所以我们真正写的代码其实只有扫描器的部分。但尽管如此,仍是把我更难住了,本来希望的设计目标是①、所有程序都跨平台。②、所有服务器都可以为多个客户端进行服务。③、扫描程序实现多线程随机扫描。④、所有程序都必须有日志记录。⑤、将TCP扫描器设计为TCP connect 扫描和TCP SYN扫描两种模式。但最终只实现了两个半:扫描程序实现多线程随机扫描、所有程序都必须有日志记录、TCP扫描器设计为TCP connect 扫描。尽管没有达到自己预定目标,但通过本次课程设计仍是让我收获很大,并且更加深刻地认识到了自己的不足。今后,本人一定要在编程方面加强。否则,真的就是心有余而力不足啊。
实验收获:
TCP/IP协议是网络中使用最广泛的协议。
Socket 套接口,最早出现在Berkeley Unix中,最初只支持TCP/IP协议族和Unix协议,现在它已支持很多协议,是最重要的网络编程接口,特别是在Unix中,其核心直接支持socket 编程,几乎所有的网络应用程序都是用Socket API来实现的。
WIN平台中,需要特别的处理并用动态库socket动态库DLL来实现。因此,需要在socket程序之外特别处理。
面向连接的TCP通信:
1,发起连接的为客户端Client ,接收连接的一方称为服务器端 Server。
2,双方的通信一般分三步:建立连接、数据传送、释放连接。
3,在传送过程中数据按顺序传送,很像电路交换,因此又称为“虚电路(VC,Virtual Circuit)服务”。
4,这是一种使用者感觉可靠的服务,但建立连接和释放连接的开销很大。
面向非连接的UDP通信:
1,互为客户端和服务器端。任何一方都可随时向对方发送或接收数据。
2,这是一种使用者感觉不可靠的服务,主要体现:报文丢失、重复或与发送顺序不一致等现象。
3,使用者一定要编写高层协议来自行解决这些问题。
4,缺点:对使用者要求高,优点:灵活、方便、效率很高(特别是对通信网络,要求低,效率高)
两者比较:
1,理论研究者为处理“不可靠”而做的选择,
面向连接:可靠性由低层服务(网络)负责,面向非连接:可靠性由用户负责。
2,能否实际通信,取决于实际的底层服务(网络)。
面向非连接的数据报达到不了对方,面向连接的通信一样也不可能(这时基本是连接都建立不起来)。
3,能否通信的“信息”:可靠性两者报告的方式不同。
面向非连接需要使用者自己“感觉”,面向连接底层服务告诉使用者。
得到“信息”的时间两者并不一定(取决于使用者 )。
4,底层(网络)为了保证“可靠”需要随时进行通信(包含互发和记录信息),这样,开销十分庞大。
特别是在使用长时间不进行实际通信时,更是极大的浪费。
理论上的结论:
1,使用者水平高、聪明时,使用面向非连接方式是明智的。
2,为了效率,使用面向非连接方式是明智的。
3,在可以容忍数据丢失的情况下,使用面向非连接方式是明智的。
如ping。如视频/语音传送。
4,如果非想随时了解线路是否可用,使用面向连接方式是明智的。
附录(程序代码部分):
附录一:(基于TCP通信的客户端与服务器)
1. wqm_TCP_S.C 代码
#include<Winsock2.h>
#include<stdio.h>
#include<time.h>
#include <sys/timeb.h>
#include <io.h>
#define socklen_t int
#pragma comment (lib, "Ws2_32.lib")
#define MyLogName "Tcp_S.log"
#pragma pack(1) //结构在存储时按字节对齐
#define ECom -100 /** 系统错误 **/
#define EPara1 -101 /** 第1个参数错误 **/
#define EPara2 -102 /** 第2个参数错误 **/
#define EMyRet -103 /** 自行退出错误 **/
#define MaxCliNo 5
/** 打印系统错误号和错误信息后返回 **/
#define SysErr(S) {perror(S);return(ECom);}
#define FFSTD fflush(stdout); /* 清除输出缓冲器. */
/** 打印地址信息 **/
#define PrAdrr(Addr) printf("%s\n",#Addr);\
printf("family:%u \n",Addr.sin_family); \
printf("addr :%08x=%s\n",Addr.sin_addr.s_addr,\
inet_ntoa(Addr.sin_addr));\
printf("port :%u,%u \n",Addr.sin_port, \
htons(Addr.sin_port));
#define SERV_PORT 26 /** 服务器服务端口 **/
#define SA struct sockaddr /** socket地址缩写 **/
#define MAXLEN 4096 /** 最大缓冲长度 **/
char ServerIP[20]="127.0.0.1";
FILE * fp;
unsigned short SPort=SERV_PORT;
unsigned short CPort;
/*01*/int DoTCPServerDisp(void); /** 没有记录 的服务程序 **/
#define Demain
int main(int argc,char *argv[])
{
int Ret=1;
printf("/***************************TCP服务器*************************/\n");
printf(" Server IP=%s Port=%d\n",ServerIP,SPort);
if((fp=fopen("Tcp_S.log","a"))==NULL)
{
printf("不能打开文件!\n");
exit(1);
}
else
{
printf("TCP服务器日志已打开!\n");
}
DoTCPServerDisp(); /** 记录接收发送数据的服务程序 **/
}
/*01*/int DoTCPServerDisp()
{
#ifdef _WIN32
WSADATA wsaData;
#endif
static SerNo=0; /**服务次数 **/
int SockFd,sAccept; /** socket 句柄 **/
int SockLen; /** socket 结构长度 **/
int iSend; /** 发送信息长度 **/
int iRecv; /** 接收信息长度 **/
#define BufLen 1024
char SBuf[BufLen]; /** 发送缓冲区 **/
char RBuf[BufLen]; /** 接收缓冲区 **/
int SendLen; /** 发送数据长度 **/
struct sockaddr_in ser,cli;
if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0) SysErr("WSAStartup() Failed!");
if((SockFd=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
SysErr("socket() Failed!");
ser.sin_family=AF_INET;
ser.sin_port=htons(SPort);
ser.sin_addr.s_addr=inet_addr(ServerIP);
printf("TCP Server Running at(Ip=%s Port=%d)\n",ServerIP,SPort);
if(bind(SockFd,(struct sockaddr*)&ser,sizeof(ser))==SOCKET_ERROR)
SysErr("bind() Failed!");
SockLen=sizeof(ser);
if(listen(SockFd,MaxCliNo)<-1) SysErr("listen() Failed!");
SockLen=sizeof(cli);
LoopAccept: /** 接受客户端连接请求 **/
sAccept=accept(SockFd,(struct sockaddr*)&cli,&SockLen);
if(sAccept==(-1)){SysErr("accept() Failed!");}
printf("Accepted client IP:[%s],prot:[%d]\n",
inet_ntoa(ser.sin_addr),
ntohs(ser.sin_port));
fprintf(fp,"Accepted client IP:[%s],prot:[%d]\n",
inet_ntoa(ser.sin_addr),
ntohs(ser.sin_port));
Loop:
iRecv=recv(sAccept,RBuf,sizeof(RBuf),0);
if(iRecv<0) {SysErr("receive error from client!\n");}
else if(iRecv==0)
{
printf(" 一个客户端结束,现在开始为下一个客户服务!\n"); //可以顺序地为多个用户服务,但前提是前一个用户必须退出
goto LoopAccept;
}
/****** 服务处理 ********/
RBuf[iRecv]=0;
sprintf(SBuf,"%s(%d:%d)SerNo=%d R(%s:%d)",
RBuf,strlen(RBuf),iRecv,++SerNo,
inet_ntoa(cli.sin_addr),ntohs(cli.sin_port));
fprintf(fp,"%s(%d:%d)SerNo=%d R(%s:%d)",
RBuf,strlen(RBuf),iRecv,++SerNo,
inet_ntoa(cli.sin_addr),ntohs(cli.sin_port));
iSend=send(sAccept,SBuf,strlen(SBuf),0);
if(iSend<-1){SysErr("send() Failed:%d\n");}
else if(iSend==0) { printf("iSend=0 Errorr?? \n");goto Loop;}
fprintf(fp,"send %s(%d) OK\n",SBuf,iSend);
goto Loop;
LEnd:
closesocket(SockFd);
WSACleanup();
return(0);
}/**** end 01 int DoTCPServer() ****/
2. wqm_TCP_C.C 代码
#in
展开阅读全文