计算机网络课程设计TCPIP协议分析及实现Word格式.doc
《计算机网络课程设计TCPIP协议分析及实现Word格式.doc》由会员分享,可在线阅读,更多相关《计算机网络课程设计TCPIP协议分析及实现Word格式.doc(15页珍藏版)》请在冰点文库上搜索。
通过设置控件的属性并调用其方法就可轻易连接到一台远程机器上去,并且还可双向交换数据。
WindowsSockets支持两种类型的套字接,即流式套字接(SOCK——STREAM)和数据报套字接(SOCK——DGRAM)。
对于要求精确传输数据的WindowsSockets通信程序,一般采用流式套接字。
流式套接字提供了一个面向连接的、可靠的、数据无错的、无重复发送的及按发关顺序接收数据的报务。
其内设流量控制,避免数据流超限,同时数据被看做是字节流,无长度限制。
流式套接字的服务进程和客户进程在通信前必须建立各自的套接字并进行了连接,然后才能对相应的套接字进行“读”、“写”操作,实现数据的传送。
会用到WindSocket的一些基本函数。
关于流式套字接具体介绍如下:
1、创建套接字——socket()
功能:
使用前创建一个新的套接字
格式:
SOCKETPASCALFARsocket(intaf,inttype,intprocotol);
af:
通信发生的区域,一般取AFI_NET
type:
要建立的套接字类型流式套字接(SOCK——STREAM)数据报套字接(SOCK——DGRAM)
procotol:
使用的特定协议,一般0,即为TCP/IP协议
2、指定本地地址——bind()
将套接字地址与所创建的套接字号联系起来。
intPASCALFARbind(SOCKETs,conststructsockaddrFAR*name,intnamelen);
参数:
s:
是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。
其它:
没有错误,bind()返回0,否则SOCKET_ERROR
地址结构说明:
structsockaddr_in
{
shortsin_family;
//AF_INET
u_shortsin_port;
//16位端口号,网络字节顺序
structin_addrsin_addr;
//32位IP地址,网络字节顺序
charsin_zero[8];
//保留}
3、建立套接字连接——connect()和accept()
共同完成连接工作
intPASCALFARconnect(SOCKETs,conststructsockaddrFAR*name,intnamelen);
SOCKETPASCALFARaccept(SOCKETs,structsockaddrFAR*name,intFAR*addrlen);
同上
4、监听连接——listen()
用于面向连接服务器,表明它愿意接收连接。
intPASCALFARlisten(SOCKETs,intbacklog);
//backlog为等待队列的最大长度
5、数据传输——send()与recv()
数据的发送与接收
intPASCALFARsend(SOCKETs,constcharFAR*buf,intlen,intflags);
intPASCALFARrecv(SOCKETs,constcharFAR*buf,intlen,intflags);
buf:
指向存有传输数据的缓冲区的指针
6、关闭套接字——closesocket()
关闭套接字s
BOOLPASCALFARclosesocket(SOCKETs);
7、字节顺序转换函数:
-----inet_addr()
将点式IP地址转换为不念旧恶32位的无符号长整数。
unsignedlonginet_addr(constcharFAR*cp)
8、WSAStartup()
功能:
加载WinsockDLL相应版本。
intWSAStartup()(WORDwVersionRequested,LPWSADATAlpWSAData);
9、WSAScleanup()
终止WinsockDLL的使用,并释放资源。
intWSACleanup(void)
3.1.2用winsock控件实现点对点通信
随着计算机和Internet网络的发展,原先在测量、控制、消费等领域不同设备/仪器之间,大多采用RS232/485或现场总线组建网络等进行数据传输的情况正在改变,特别在要求数据传输速度和可靠性方面的应用产品,转向基于Internet网络的远程传输和应用。
网络编程大多基于TCP/IP协议,实现方法有多种,复杂但编程适应性广的方法是调用底层的Winsock
API函数或MFC基本类等;
简单方便的方法可以采用如Winsock控件。
在网络编程中最常用的方案便是客户机/服务器模型,客户应用程序向服务器程序请求服务。
另外一种模式是点对点通信,通信双方对等,既有客户机功能又有服务器的功能,编程简单,适合传输数据流少的场合,而且采用简单的UDP协议,易于用微控制器等嵌入式系统实现,在测量控制方面有许多应用。
接下将介绍一些网络编程和Winsock控件知识,用VC++实现点对点通信。
3.1.3网络通信协议基础
Winsock控件支持两种协议,TCP协议和UDP协议,都属于用TCP/IP协议。
TCP(TransferControlProtocol)是传输控制协议的简称,是基于连接的协议,在数据传输之前必须先建立连接,通信双方是基于客户/服务器模型,必须分别建立客户应用程序和服务器应用程序。
UDP(用户数据文报协议)协议是一种无连接协议,通信双方之间的传输类似于传递邮件:
消息从一方发送到另一方,但是两者之间没有明确的连接,通信双方是对等的,单次传输的最大数据量取决于具体的网络。
本设计是使用TCP的服务类型。
利用Winsock控件创建双方的通信过程如下(以TCP为例):
首先服务器端的应用程序先要运行,并且进行端口号的设置,然后进入等待,即等待客户端应用程序的连接请求;
然后客户端的应用程序开始运行,向服务器发送信息,在服务器端会以消息对话框的形式显示这些信息;
然后服务器端的应用程序会把这些信息再次地传回给客户端的应用程序,同样以消息对话框的形式显示出来。
3.1.4二进制数据点对点通信的实现
基于网络的远程控制和测量应用中,一般数据传输采用二进制格式,双机之间的连接方式是主丛式,构建一个测控网络,从机之间如果要交换数据也得通过主机。
在网络测量控制等领域,通信双方需要传输的数据流量少,下位机一般是微控制器等嵌入式系统,数据处理能力较慢,通信双方也不必保持紧密联系,因此大多采用UDP协议,基于点对点的方式,双方通信的数据可靠性可以通过定义数据表示格式来保证。
为了描述如何应用,我们在这里建立一个基于对话框的简单的点对点通信例子,说明在VC++中如何用Winsock控件实现二进制数据点对点通信。
3.2典型过程图
面向连接的流式套接字的系统调用模式图
四、方案设计
通过以上理论的学习,我设计了此双向通信的C/S程序。
其设计思路基本如下:
客户机/服务器模式
客户端应用程序主要功能是:
建立到服务器的连接,向服务器发送信息,接收从服务器发来的回传信息,关闭与服务器的连接。
服务器端应用程序主要功能是:
创建监听Socket进行监听,在有客户进行连接请求时会创建一个新的接收的Socket处理这个客户得数据发送和接收(此部分最多可接收和处理5个客户的连接请求)。
五、设计结果
运行前的准备:
获取主机IP地址。
具体方法是在运行窗口中运行cmd命令(如图1)。
图1
接着输入ipconfig命令,即可获得所需地址(如图2)。
图2
正式运行:
先运行服务器端程序,进行网络的端口号设置,如图3
图3
接着运行客户端程序,进行连接,当正确运行时,系统会弹出连接成功的对话框,接着即可发送消息(如图4)。
图4
然后,服务器端弹出提示信息(如图5),最后,客户端弹出提示信息(如图6)。
图5图6
以上就是一次完整的通信过程。
六、源代码(含有注释)
服务器端:
AcceptSocket.cpp
//AcceptSocket.cpp:
implementationfile
#include"
stdafx.h"
Server.h"
//自己添加的成员函数
AcceptSocket.h"
MainFrm.h"
#ifdef_DEBUG
#definenewDEBUG_NEW
#undefTHIS_FILE
staticcharTHIS_FILE[]=__FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
//CAcceptSocket
CAcceptSocket:
:
CAcceptSocket(CMainFrame*pMainFrame)
{
m_pMainFrame=pMainFrame;
//进程框架对象的赋值
}
~CAcceptSocket()
}
//Donoteditthefollowinglines,whichareneededbyClassWizard.
#if0
BEGIN_MESSAGE_MAP(CAcceptSocket,CSocket)
//{{AFX_MSG_MAP(CAcceptSocket)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif //0
//CAcceptSocketmemberfunctions
voidCAcceptSocket:
OnReceive(intnErrorCode)
{
charpMsg[10000],tempMsg[1000];
intByteCount;
//每次读取的字符个数
intEndFlag=0;
//接受完后的标志
charAnswerMsg[10100];
//回应信息字符串
strcpy(pMsg,"
"
);
do
{
strcpy(tempMsg,"
//每次读取时,把读取使用的缓冲区置成空
ByteCount=Receive(tempMsg,1000);
//每次读取1000个字符
if(ByteCount>
1000||ByteCount<
=0)
{
AfxMessageBox("
接受数据出错"
MB_OK);
return;
}
elseif(ByteCount<
1000&
&
ByteCount>
0)
{
EndFlag=1;
//字节不足1000时,表示数据接受已经完成
//添加字符串的结束苻
tempMsg[ByteCount]=0;
//把每次收到的数据放在一起
strcat(pMsg,tempMsg);
}while(EndFlag==0);
//显示接收但的数据
AfxMessageBox(pMsg,MB_OK);
sprintf(AnswerMsg,"
我已经收到你的消息\n\"
%s\"
\n谢谢"
pMsg);
//发送回传信息
Send(AnswerMsg,strlen(AnswerMsg),0);
CSocket:
OnReceive(nErrorCode);
ListenSocket.cpp
//ListenSocket.cpp:
//
ListenSocket.h"
//CListenSocket
//构造函数和析构函数的实现
CListenSocket:
CListenSocket(CMainFrame*pMainFrame)
{
//进程框架对象的赋值
}
~CListenSocket()
BEGIN_MESSAGE_MAP(CListenSocket,CSocket)
//{{AFX_MSG_MAP(CListenSocket)
//CListenSocketmemberfunctions
voidCListenSocket:
OnAccept(intnErrorCode)
//生成接收Socket函数
CAcceptSocket*pSocket=newCAcceptSocket(m_pMainFrame);
//如果监听成功了,则通过框假类的成员函数
//把接收的socket放入接收socket队列
if(Accept(*pSocket))
{
m_pMainFrame->
m_pAcceptList.AddTail(pSocket);
else//否则进行错误处理
deletepSocket;
CSocket:
OnAccept(nErrorCode);
}
MainFrm.cpp
//MainFrm.cpp:
implementationoftheCMainFrameclass
//以下是自己添加的头文件
SetPortDlg.h"
//CMainFrame
IMPLEMENT_DYNCREATE(CMainFrame,CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_COMMAND(ID_SET_PORT,OnSetPort)
staticUINTindicators[]=
ID_SEPARATOR,//statuslineindicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
//CMainFrameconstruction/destruction
//构造函数和析够函数的实现
CMainFrame:
CMainFrame()
//TODO:
addmemberinitializationcodehere
m_pListenSocket=NULL;
//初始化请求Socket
m_pAcceptList.RemoveAll();
~CMainFrame()
//释放监听空间
deletem_pListenSocket;
intCMainFrame:
OnCreate(LPCREATESTRUCTlpCreateStruct)
if(CFrameWnd:
OnCreate(lpCreateStruct)==-1)
return-1;
if(!
m_wndToolBar.CreateEx(this,TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_TOP
|CBRS_GRIPPER|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC)||
!
m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
TRACE0("
Failedtocreatetoolbar\n"
//failtocreate
}
m_wndStatusBar.Create(this)||
!
m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
Failedtocreatestatusbar\n"
Deletethesethreelinesifyoudon'
twantthetoolbarto
//bedockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&
m_wndToolBar);
return0;
BOOLCMainFrame:
PreCreateWindow(CREATESTRUCT&
cs)
if(!
CFrameWnd:
PreCreateWindow(cs))
returnFALSE;
ModifytheWindowclassorstylesherebymodifying
//theCREATESTRUCTcs
returnTRUE;
//CMainFramediagnostics
voidCMainFrame:
AssertValid()const
CFrameWnd:
AssertValid();
Dump(CDumpContext&
dc)const
Dump(dc);
#endif//_DEBUG
//CMainFramemessagehandlers
//"
响应端口号设置采单命令的响应处理函数"
OnSe