基于TCPIP的SOCKET接口实现网络通信.docx
- 文档编号:11984144
- 上传时间:2023-04-16
- 格式:DOCX
- 页数:18
- 大小:22.37KB
基于TCPIP的SOCKET接口实现网络通信.docx
《基于TCPIP的SOCKET接口实现网络通信.docx》由会员分享,可在线阅读,更多相关《基于TCPIP的SOCKET接口实现网络通信.docx(18页珍藏版)》请在冰豆网上搜索。
基于TCPIP的SOCKET接口实现网络通信
基于TCP/IP的SOCKET接口实现网络通信
姜文平 谭 晖
(湖北省邮电科学研究院 430010)
摘 要 在简单说明基于TCP/IP的SOCKET编程的基本原理的基础上,介绍了在UNIX环境下怎样编写客户端和服务器端的通信模块的方法,以及VisulC++5.0提供的SOCKET编程机制。
关键词 TCP/IP SOCKET 接口 编程 计算机软件 网络通信
基于TCP/IP的SOCKET通令编程接口由4BSD UNIX首先提出,它只能用于UNIX系统。
随着微机应和越来越广泛,SOCKET在UNIX的成功应用使得将SOCKET移植到DOS和WIDOWS下成为一件有意义的工作,因此在90年代初,SUNMICROSYSTEM、JSBCORPORATION、FTPSOFTWARE、MICRODYNE以及MICROSOFT等共同制定了一套标准,即WIDOWSSOCKETS规范,把SOCKET机制引入了WIDOWS,先后推出了WINSOCK1.0、WINSOCK1.1、WINSOCK2.0,由于WIDOWS操作系统与UNIX系统任务调度方式的区别,WINSOCK除了可以兼容UNIX和SOCKET编程接口外,又把它加以扩展以适合WIDOWS文件驱动特性。
由于WINDOWS编程方法相对复杂,为此,现在提供的编程语言中,都将该机制封装到类中,通过类来编写基于WINDOWS/NT下的网络通信程序。
下面我们分别介绍SOCKET通信的有关概念,以及UNIX下的SOCKET编程和基于WINDOWS/NT开发工具提供的SOCKET编程方法。
一、基于TCP/IP的SOCKET编程的基本原理
利用基于TCP/IP的SOCKET通信编程接口编写程序,其目的是在TCP/IP所组建网络的不同机器之间利用客户/服务器模式建立通信连接。
为建立该连接,开发人员只要提供一些基本的连接信息,其余由操作系统内核来完成。
下面我们来讨论建立一个完整通信连接开发者需要提供的信息。
以机器A通过TCP/IP与机器B进行网络通信为例,对于机器A来说我们需要知道如下信息:
(1)机器B的TCP/IP地址;
(2)与机器B中哪一个进程(或软件系统)联系。
以上两个需要的参数,第一个显然可以被大家理解,但第二个也许有人存在疑问,因为象电子邮件收发、TELNET、PING等基本的TCP/IP网络应用程序,在建立连接时都只要提供TCP/IP地址(或者对应域名地址),根本没有必要提供第二个参数,这是为什么呢?
其实原因很简单,就是它们使用的是一些标准接口,第二个参数早就定义了,这些应用系统在发出呼叫请求前,自己已经知道该与对方怎样联系,在发请求前,自动将第二个参数加入请求中。
如果开发者也要开发这样的系统,就需要知道这些标准接口;对于那些需要建立专用系统网络连接的,却需要双方协商。
以上两个需要提供的参数,在套接字中分别表示为机器B的地址和机器B的通信端口。
通过在同一机器的不同通信软件中定义不同端口地址,来表示机器A是与机器B中哪套系统通信。
不管是利用何种协议,完全建立一个网络连接需要五个基本信息。
它们分别是双方的地址、约定的通讯端口和协议类型。
SOCKET通信编程接口并不是专门为TCP/IP通信提供的,因此套接字通信编程需要在参数中指明通信协议类型。
套接字是利用客户/服务器模式来实现通信的,客户端软件和服务器端软件的具体实现也有所不同。
具体来说,在客户端利用基于TCP/IP和SOCKET通信编程的基本步骤是:
①声明一个套接字类型的变量,需要在该变量定义中提供本机IP地址和通信端口并指明协议类型,由于在此介绍的是基于TCP/IP的套接字通信,因此协议类型应该是TCP/IP,在编程接口中该类型用AF-INET来表示;②向对方发出连接请求,连接时编程者需要提供对方TCP/IP地址和通信端口,同时SOCKET实现程序自动向对提供本机TCP/IP地址和通信端口;③如果连接成功,会收到对方的应答信号,这以后的通信就可以通过套接字的相关操作来实现了。
利用SOCKET来实现服务器端通信软件的步骤是:
①同客户端程序第1个步骤;②服务器端通信软件进入等待客户端连接的状态,如果收到连接,则从对方连接请求中获取对方的IP地址和通信端口,并向对方发送连接成功的应答信号。
由上面的介绍可知,客户端与服务器端通过SOCKET通信都需要知道5个基本信息,不同的是客户端软件开发者需要向编程接口全部提供5个参数,而服务器端软件开发者只需要提供3个。
需要注意的是客户端和服务器端所提供的本地端口地址可以相同,可以不同,但客户端口地址可以动态分配,而服务器端端口地址必须固定,否则连接就不能建立。
下面介绍在不同编程语言中编写与客户端和服务器端的通信模块。
二、UNIX下通过SOCKET实现面向连接的网络通信
下面分别介绍在UNIX环境下编程时,怎样编写客户端和服务器端的通信模块。
1.客户端通信模块
(1)步骤一,定义套接字变量
在UNIX中是通过结构sockaddr_in来定义套接字通信的基本信息(该结构的详细内容请参见有关资料),然后通过该结构由系统分配一套接字。
我们声明客户端相关变量如下:
structsockaddr_inClientSocketAddr;/*本机通信地址信息变量*/
structsockaddr_inServerSocketAddr;/*服务器通信地址信息*/
int ClientSocket; /*套接字句柄变量,也就是系统分配的套接字*/
intret,socklen;
(2)步骤二,初始化相关信息,并向系统请求分配套接字
对应程序如下:
ClientSocketAddr.sin_port=htons(2086);/*指定通信端口为2086,并将端口号转换成为网络字节顺序*/
ClientSocketAddr.sin_addr.s_addr=0x81010101f;/*本机IP地址:
129.1.1.31,该语句赋值也可用inet_addr(“129.1.1.31”)代替*/
ClientSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);/*分配套接字,参数含义见有关参考书,对于基于TCP/IP编程来说,固定使用该格式调用就可以了*/
if(ClientSocket<0)/*分配失败的原因一般是系统资源不够引起的*/
{
perror(“Can'tallocateanewsocket!
\n”);
return;
}
socklen=sizeof(ClientSocketAddr);/*sockaddr_in结构的长度是在不同环境下是不同的,故在此取其大小*/
ret=bind(socketid,&ClientSocketAddr,socklen);/*将套接字与本机的地址信息结合(绑定)起来*/
if(ret==-1)/*绑定失败一般是由于IP地址不正确或者对应通信端口已经与别的套接字绑定了引起的*/
{
perror(“Can'tbindthenewsockettosocketaddress”);
close(socketid);
return;
}
指定通信端口为2086时,如果不指定一具体端口,该值可以用系统定义常量INADDR_ANY来代替,表示由系统分配任意一个空闲的套接字,这种方式对于客户端来说应该还要保险些。
因为指定端口可能被别的系统占用,这时系统就不能分配该端口对应的套接字给本部分程序,导致下面的分配失败。
(3)向服务器端发出连接请求
ServerSocketAddr.sin_port=1088;/*指定服务器通信端口为1088*/
ServerSocketAddr.sin_addr.s_addr=inet_addr(“129.1.1.10”);/*服务器IP地址:
129.1.1.10*/
connect(ClientSocket,&ServerSocketAddr,sizeof(ServerSocketAddr));
2.服务器端通信模块
(1)步骤一和二同客户端程序
下面列出对应C程序:
intServerSocket,ret,socklen,newsocket,clientsocklen;+structsockaddr_inServerSocketAddr,ClientSocketAddr;
ServerSocketAddr.sin_family=AF_INET;
ServerSocketAddr.sin_port=htons(1088);/*将端口号转换成为网络字节顺序*/
ServerSocketAddr.sin_addr.s_addr=inet_addr(“129.1.1.10”);/*将IP地址串转换成为内部表示地址信息*/
ServerSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);/*分配服务器套接字*/
if(ServerSocket<0)
{
perror(“Can'tallocateanewsocket!
n”);
return;
}
socklen=sizeof(ServerSocketAddr);
ret=bind(ServerSocket,&ServerSocketAddr,Socklen);/*将该套接字与服务器通信地址信息绑定*/
if(ret==-1)
{
perror(“Can'tbindthenewsockettosocketaddress”);
close(ServerSocket);
return;
}
(2)步骤三,进入监听客户端连接请求状态,并进入等待客户连接请求状态
if(listen(ServerSocket,5)<0)/*建立长度为5的请求队列,以允许多个五个客户端同时连接/*
{
perror(“Listenerror;”);
close(ServerSocket);
return;
}
for(;;)
{
newsocket=accept(ServerSocket,&sockaddr,&socklen);/*监听客户连接请求,如果没客户端连接,程序将一直在此等待*/
/*连接建立后,用生成的新套接字来处理当前连接请求,而原来监听的套接字继续监听别的连接请求*/
if(newsocket<0)
{
perror(“Acceptrequestfailure”);
close(ServerSocket);
return;
}
if(fork()==0)/*生产子进程来处理连接后的任务*/
}
close(ServerSocket);
DO{
…… /*执行连接以后的通信任务*/
}/*fork 结束*/
}/*循环体结束*/
三、VisulC++5.0提供的SOCKET编程机制
在VisulC++5.0中提供了CAsyncSocket、CSocket等MFC类来实现网络通信,其中CSocet类是CAsyncSocket的派生类,它更适合于不需要对网络编程了解太深的应用开发。
下面以CAsyncSocket类为例来介绍VisulC++5.0中套接字编程的实现。
在使用CAsyncSocket时,最好是从该类派生一新类,以便于开发者接管CAsyncSocket的消息机制,这样开发者可以重写这些消息响应方法,以进行适合自己的处理,这些响应方法包括:
.virtualvoidOnClse(intnErrorCode);//收到对方端开连接时的响应方法
.virtualvoidOnConnect(intnErrorCode);//客户端向对方发出连接请求后收到对方应答时的响应方法
.virtualvoidOnAccept(intnErrorCode);//服务器端可以接收客户连接请求时的响应方法
.virtualvoidOnReceive(intnErrorCode);//收到对端传送数据消息时的响应方法
.virtualvoidOnSend(intnErrorCode);//可以向对端发送数据时的响应消息
下面具体介绍利用CAsyncSocket来实现网络通信的编程方法。
在介绍时,将同时介绍服务器端与客户端实现的有关内容。
为此,下面分别介绍类CMySocket、CClientSocket、CServerSocket,其中类CMySocket是从CAsyncSocket派生的,而后两者都是从CMySocket派生的,分别用来开发客户端和服务器通信程序。
在此首先介绍CMySocket的定义文件内容:
//DefinitionofCMysocketFile:
Socket.h
classCMySocket:
publicCAsyncSocket
{
//Attributes
public;
char LocalIP[20];//本机IP地址
char RemoteIP[20];//对端IP地址
//Operations
public;
CMySocket(LPCTSTRLIP,INTLPort=0,LPCTSTRRIP=NULL,INTRPort=0);//构造函数,参数分别为本机IP地址、本地端口、对端IP地址、对端端口
virtualCMySocket();//析构函数
BOOLaccept();
BOOLconnect();
assWizardgeneratedvirtualfunctionoverrides
//{{AFX_VIRTUAL(CMySocket)
public:
//重写的响应方法
virtualvoidOnClose(intnErrorCode);
virtualvoidOnConnect(intnErrorCode);
virtualvoidOnAccept(intnErrorCode);
virtualvoidOnReceive(intnErrorCode);
virtualvoidOnSend(intnErrorCode);
//}}AFX_VIRTUAL
protected;
UINT RemotePort;
UINT LocalPort;
SOCKADDR_IN RemoteAddress;
int AddressLen;
classCMySocketNewSocket;//服务器端监听连接使用
};
CMySocket实现文件的内容:
//implementionofCMySocket:
Socket.cpp
#include“Socket.h”
CMySocket;;CMySocket()
{
}
CMySocket:
:
CMySocket(IPCTSTRLIP,INTLPort,IPCTSTRLIP,INTRPort)
{
strcpy(LocalIP,LIP);
LocalPort=LPort;
if(RIP)
{
Strcpy(RemoteIP,RIP);
RemotePort=htons(RPort);
RemoteAddress.sin_addr.s_addr=inet_addr(RemoteIP);
RemoteAddress.sin_family=AF_INET;
RemoteADDress.sin_port=RemotePort;
}
else
strcpy(RemoteIP,“0”);
IF(!
Create(LPort,SOCK_STREAM,FD_READ|FD_ACCEPT|FD_CONNECT|FD_CLOSE,LocalIP))
{
//创建套接字失败则
……
}
}
voidCMySocket:
:
OnClose(intnErrorCode)
{
//收到对方端开连接信息时的相关处理
……
CAsyncSocket:
:
OnClose(nErrorCode);
}
voidCMySocket:
:
OnClose(intnErrorCode)
{
//TODO:
Addyourspecializedcodehereand/orcallthebaseclass
charmy_buff[180];
strcpy(my_buff-“运行信息nn”);
IsConnectingFront=false;
if(nErrorCode)
{
//不能建立连接时的处理
……
}
else
{
//连接建立成功后的处理
……
}
CAsyncSocket:
:
OnClose(nErrorCode);
}
voidCMySocket:
:
OnClose(intnErrorCode)
{
accpt();
CAsyncSocket:
:
OnClose(nErrorCode);
}
voidCMySocket:
:
OnClose(intnErrorCode)
{
charbuff[1024];
inti;
if(nErrorCode==0)
{
memset(buff,0,1024);
i=Receive(buff,1024,!
MSG_OOB);
……//收到数据后的相关处理
}
CAsyncSocket:
:
OnClose(nErrorCode);
}
voidCMySocket:
:
OnClose(intnErrorCode)
{
……//可以发送时的相关处理
CAsyncSocket:
:
OnClose(nErrorCode);
}
BOOLClientSocket:
:
connect(){returnConnect(RemoteIP,RemotePort);})
BOOLClientSocket:
:
accept()
{
BOOLi;
AddressLen=sizeof(RemoteAddress)+8;
i=Accept(NewSocket,(structsockaddr*)&RemoteAddress,&AddressLen);
returni;
}
在定义了CMySocket类的基础上,就可以正式编写通信代码。
(1)客户端代码
CMySocketClientSocket(“129.1.1.31”,2086,“129.1.1.10”,1088);//分配并初始化套接字
ClientSocket.connect();//向服务器端发出连接请求
在连接成功后,基于响应方法进行有关通信处理。
(2)服务器端代码
CMySocketClientSocket(“129.1.1.10”,1088);//分配并初始化
ServerSocket.Listen();//创建监听队列
此后,基于响应方法进行有关通信处理。
四、C+ +BUILDER3.0提供的SOCKET编程接口
C+ +Builder是新一代可视化面向对象的开发工具,它的核心是封装了各种属性和方法的抽象类。
在socket网络开发中主要应用TClientSocket和属性和方法的抽象类。
在socket网络开发中主要应用TClientSocket和TClientSocket两种可视化抽象类,其中TClientSocket类对应客户端,TClientSocket对应服务器端。
下面介绍TClientSocket类及TClientSocket一些较重要的属性:
Socket:
Socket通讯实体。
Active:
表明TClientSocket或TSrverSocket是否可用,在改变socket连接接或用socket连接通讯时,都应确定该属性是否为真。
在socket连接存在情况下,如果客户端将Active属性置为假时,该socket连接将中断,服务器端将继续监听,并等待客户端的连接请求;如果服务器端将Active连接将中断,服务器端将停止监听。
Port:
连接所用的端口号。
Address:
IP地址。
对于客户端,该IP地址为须连接端IP地址。
ClientType:
说明该连接服务为阻塞式连接还是非阻塞式连接。
阻塞式连接程序须等待网络数据读写完成。
非阻塞式连接不须等待网络数据读写完成,当网络数据来临时,系统会向应用程序发出某种消息。
应用程序可根据该消息对网络数据进行处理。
ThreadCacheSize:
服务器端可同时维持的独立连接总数。
1.客户端程序编制步骤
(1)设置ClientType属性为ctNonBloc-king,设置被连接端IP地址和连接所用端口号;
(2)将Active属性置为true或利用TClientSocket抽象类中的Open方法与服务器端建立连接;
(3)在OnReading事件响应函数中加入响应接收网络数据的处理方法;
(4)发送数据前,先判断Active属性是否为true,是则利用Socke的ReceiveBuf方法发送数据;
(5)中断连接只须将Active属性置为false或利用TClientSocket抽象类中的Close方法。
客户端程序可以如下例所示:
TClientSocketClentSocket1;
…
ClientSocket1->ClentType=cnNonBlocking;
ClientSocket1->Port=8088;
ClientSocket1->Address=”133.8.5.200”;
…
if(ClientSocket1->Active!
=true)/*判断该连接是否可用*/
ClientSocket1->Open();/*若不可用,建立该连接*/
…
void_fastcallTForm1:
:
ClentSockt1Read(TobjectSender,/*OnReading事件响应函数*/
TCustomWinsocket*Socket)
{
charbuff[1024];
…
memset(buff,0,1024);/*初始化授受缓冲区*/
ClientSocket1->Socket->ReceiveBuf(buff,1024);/*接受数据*/
…
}
…
if(ClientSocket1->Active==true)/*判断该连接是否可用*/
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 TCPIP SOCKET 接口 实现 网络 通信
![提示](https://static.bdocx.com/images/bang_tan.gif)