使用C(或C++)语言编写网络通信模拟程序

一、实验目的

熟悉和掌握网络编程的基本方法和步骤;进一步理解 client/server 交互模式;加深学生对于网络协议概念的理解以及协议的设计和实现方法。

 

二、设备与环境

微型计算机、Windows 系列操作系统 、Visual C++6.0软件

 

三、实验内容

使用C(或C++)语言编写网络通信模拟程序,它由 client 和 server 两部分组成, client 和 server 之间的通信基于 TCP 或者UDP协议,要求能够实现客户和服务器端的交互对话。

具体:

1) 服务器和客户端有提示;

2) 服务启动后处于监听状态等待客户机连接,当有客户连接时给出提示,并   显示客户IP地址,并给客户端发送问候消息;

3) 客户机端要求启动后主动连接服务器,也可以通过菜单控制连接的时机,   连接成功后给出提出;

4)在通信连接建立之后,客户和服务器双方可以进行联系的消息传递,直至一方发送quit消息,断开连接。

5)要求界面尽量友好,功能尽量完善,可考虑增加功能菜单,提高系统的交互性。

6) 对功能进行适当分解,用若干函数完成系统

 

 

四、实验结果及分析

  1、变量定义:

    (1)需要定义套接字类型变量,因为套接字存在于地址族中,可以将通过套接字通信的进程的公有特性综合在一起。套接字通常只与同一区域的套接字交换数据。Windows Sockets只支持AF_INET网络域,使用网际协议族通信的进程使用该域。因此只有将数据转换成Socket类型的数据才可以进行传输。

 

    (2)定义地址结构体,用于存储协议族、ip地址以及端口号。其中,在地址结构体sockaddr_in中的sin_family部分指代协议族,也用于存放协议族信息,这一项在socket编程中只能是AF_INET,地址结构体sockaddr_in中的sin_addr部分用于存储ip地址,而sin_port部分则用于存储端口号

 

 

    (3)定义双字节型数值Socket版本,这里必须要提及MAKEWORD函数,MAKEWORD函数的作用是将两个byte类型合并成一个双字节型,其中一个在高8位,另一个在低8位。将MAKEWORD函数合并成的双字节型值赋给双字节型数值sockVersion作为Socket版本。

 

 

    (4)定义WSADATA类型的值,用来存储返回的Sockets数据。WSADATA是一种数据结构。这个结构被用来存储被WSAStartup函数调用后返回的Windows Sockets数据。

 

 

  2、函数介绍:

    在server程序中:

  1. 服务启动函数start():
    1. 该函数用于启动服务器,若启动成功返回0,启动失败则返回-1。其中应用到了WSAStartup函数,作用是启动WSA,这个函数的第一个参数为程序请求使用的Socket版本,第二个参数为返回请求的版本信息,返回值为0时成功。
    2. Socket函数用于根据指定的地址族、数据类型和协议来分配一个套接口的描述字及其所用的资源,3个参数分别为协议族、套接字类型和协议。另外,将对应的值分别存储到地址结构体中专门存放协议族、ip地址以及端口号的sin_family、sin_addr和sin_port。
    3. 除此之外,start()函数中还用到了库函数bind(),bind函数的作用是把socket与协议、ip地址、端口号绑定起来,由于bind函数的返回值表示绑定操作是否成功(0表示成功, -1表示不成功),因此可以对bind函数用if语句判断。bind函数中的第一个参数是待绑定的套接字,第二个参数是标识绑定在哪个“地方”,第三个参数则是这个“地方”的占地大小                                                                                                                                                                 
    4. start函数中还用到了listen(),listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。listen函数的第一个参数表示被listen函数作用的套接字,第二个参数表示队列内核的上限。另外,listen函数返回值表示侦听是否成功(0表示成功, -1表示不成功),因此也可以对listen函数用if语句判断。

 

 

 

 

  1. 服务停止函数stop():                                                                                                                                                                                           该函数用于停止服务器,首先对startOK的值进行判断,若startOK的值已经被赋为0(服务器已经启动),则开始关闭服务器。               其中涉及到了closesocket函数,closesocket函数的作用和socket函数的作用相反,释放为套接字分配的资源。                                         而另一个用到的函数WSACleanup()则和WSAStartup函数的作用相反,终止对WSA的使用。

 

 

 

  1. 接收客户端连接函数acceptClient():
    1. 该函数用于接收客户端连接,其中涉及到的accept函数则用于接收客户端的请求,accept函数第一个参数是待连接的套接字,第二个参数是待连接地址结构体的“位置”,第三个参数则是地址指向“位置”的长度。
    2. 另外,inet_ntoa()为IP地址转换函数,用于把网络字节序IP转化点分十进制IP。而send()函数则用于发送数据,应用程序使用send函数向TCP连接的另一端发送数据,其中尤其需要注意的是send()函数的第四个参数,第四个参数为flags,一般置0。
    3. kbhit()函数是一个系统自带的库函数,用于判断键盘是否有按下,若键盘有按下则返回1,若键盘没有按下则返回0。
    4. acceptClient()函数中使用到的setsockopt()函数则用于套接口设置选项值,其中第一个参数是待设置的套接字,第二个参数表示选项定义的层次,第三个参数表示需设置的选项,其中SO_RCVTIMEO指超时时间,第四个参数表示指向存放选项值的缓冲区的指针,第五个参数则表示缓冲区长度,也就是int类型的长度。
    5. recv函数用于接收客户端的数据,其中需要注意的是它的第三个参数表示缓冲区长度,也就是最长能接收的缓冲数据量,第四个参数send()函数相同,意思也是为flags,一般也置0 。

 

 

 

 

 

 

  1. 菜单函数menu():                                                                                                                                                                                                     仅仅用于输出菜单。
  2. 主函数main():                                                                                                                                                                                                           使用while(1)来执行无限循环,并输出菜单。根据输入的值不断调用之前的那几个函数,当输入5时,执行exit(0)退出。

在client程序中:

  1. 连接服务器函数connectServer():
    1. 该函数用于连接服务器,若启动成功返回0,启动失败则返回-1。其中应用到了WSAStartup函数,作用是启动WSA,这个函数的第一个参数为程序请求使用的Socket版本,第二个参数为返回请求的版本信息,返回值为0时成功。
    2. Socket函数用于根据指定的地址族、数据类型和协议来分配一个套接口的描述字及其所用的资源,3个参数分别为协议族、套接字类型和协议。另外,将对应的值分别存储到地址结构体中专门存放协议族、ip地址以及端口号的sin_family、sin_addr和sin_port。
    3. 除此之外,connectServer()函数中还用到了库函数connect(),connect函数用于连接服务器,其中第一个参数是客户端的套接字,第二个参数是服务端的套接字所在的“地方”,第三个参数是该“地方”的大小,如果请求连接成功,则返回0,否则返回错误码。                                              
    4. connectServer函数中还用到了inet_ntoa函数,inet_ntoa()为IP地址转换函数,用于把网络字节序IP转化点分十进制IP。

 

 

 

 

 

  1. 服务器对话函数ChatWithServer():
    1. ChatWithServer函数中用到了kbhit函数,kbhit()函数是一个系统自带的库函数,用于判断键盘是否有按下,若键盘有按下则返回1,若键盘没有按下则返回0。
    2. 其中通过判断connectOK的值来判断服务器是否已经连接,若connectOK的值为0则表示已经与服务器连接,可以进行接下来的对话步骤。
    3. buf缓冲区变量存放着要发送的数据,用gets函数来读字符串。首先用系统自带函数kbhit(),来判断键盘是否有按下,与之前相同,若键盘有按下,则读取缓冲区中要发送的数据,并调用send()函数。应用程序使用send函数向TCP连接的另一端发送数据。
    4. 对输入的数据进行判断,若输入的数据为"bye"、"再见"或者是"quit",则调用清屏函数,并输出菜单和停止函数。
    5. 设置recv的超时时间,超时则返回,不等待。这需要用到setsockopt函数,setsockopt()函数用于套接口设置选项值,它的第一个参数是待设置的套接字,第二个参数表示选项定义的层次,第三个参数表示需设置的选项,其中SO_RCVTIMEO指超时时间,第四个参数表示指向存放选项值的缓冲区的指针,第五个参数则表示缓冲区长度,也就是int类型的长度。
    6. 另外,还用到了recv(),recv函数用于接收客户端的数据,其中需要注意的是它的第三个参数表示缓冲区长度,也就是最长能接收的缓冲数据量,第四个参数send()函数相同,意思也是为flags,一般也置0 。
    7. 最后,用if进行判断,如果接收到的数据长度>0,则输出recvBuf[]中的数据并显示。对接收到的数据进行判断,若接收到的数据为"bye"、"再见"或者是"quit",则调用清屏函数,并输出菜单和停止函数。

 

 

 

 

 

  1. 客户端停止函数stop():
    1. 该函数用于停止客户端,首先对sockClient的值进行判断,若sockClient的值为1(客户端已经启动),则开始关闭客户端。其中涉及到了closesocket函数,closesocket函数的作用和socket函数的作用相反,释放为套接字分配的资源。
    2. 而另一个用到的函数WSACleanup()则和WSAStartup函数的作用相反,终止对WSA的使用。

 

 

 

  1. 菜单函数menu():                                                                                                                                                                                       仅仅用于输出菜单。
  2. 主函数main():                                                                                                                                                                                           使用while(1)来执行无限循环,并输出菜单。根据输入的值不断调用之前的那几个函数,当输入5时,执行exit(0)退出。

 

你可能感兴趣的:(使用C(或C++)语言编写网络通信模拟程序)