UDPTCP客户服务员程序设计Word文档格式.docx
- 文档编号:17197401
- 上传时间:2022-11-28
- 格式:DOCX
- 页数:13
- 大小:57.15KB
UDPTCP客户服务员程序设计Word文档格式.docx
《UDPTCP客户服务员程序设计Word文档格式.docx》由会员分享,可在线阅读,更多相关《UDPTCP客户服务员程序设计Word文档格式.docx(13页珍藏版)》请在冰豆网上搜索。
/*32位IP地址,网络字节顺序*/
charsin_zero[8];
/*保留*/
}
(c)套接字类型
TCP/IP的socket提供下列三种类型套接字。
流式套接字(SOCK_STREAM)
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复地发送,且按发送顺序接收。
内设流量控制,避免数据流超限;
数据被看作是字节流,无长度限制。
文件传送协议(FTP)即使用流式套接字。
数据报式套接字(SOCK_DGRAM)
提供了一个无连接服务。
数据包以独立包形式被发送,不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。
网络文件系统(NFS)使用数据报式套接字。
原始式套接字(SOCK_RAW)
该接口允许对较低层协议,如IP、ICMP直接访问。
常用于检验新的协议实现或访问现有服务中配置的新设备。
(d)基本套接字系统调用
为了更好地说明套接字编程原理,下面给出几个基本套接字系统调用说明。
(1)创建套接字──socket()
应用程序在使用套接字前,首先必须拥有一个套接字,系统调用socket()向应用程序提供创建套接字的手段,其调用格式如下:
SOCKETsocket(intaf,inttype,intprotocol);
该调用要接收三个参数:
af、type、protocol。
参数af指定通信发生的区域,UNIX系统支持的地址族有:
AF_UNIX、AF_INET、AF_NS等,而DOS、WINDOWS中仅支持AF_INET,它是网际网区域。
因此,地址族与协议族相同。
参数type描述要建立的套接字的类型。
参数protocol说明该套接字使用的特定协议,如果调用者不希望特别指定使用的协议,则置为0,使用默认的连接模式。
根据这三个参数建立一个套接字,并将相应的资源分配给它,同时返回一个整型套接字号。
因此,socket()系统调用实际上指定了相关五元组中的“协议”这一元。
(2)指定本地地址──bind()
当一个套接字用socket()创建后,存在一个名字空间(地址族),但它没有被命名。
bind()将套接字地址(包括本地主机地址和本地端口地址)与所创建的套接字号联系起来,即将名字赋予套接字,以指定本地半相关。
其调用格式如下:
intbind(SOCKETs,conststructsockaddrFAR*name,intnamelen);
参数s是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。
参数name是赋给套接字s的本地地址(名字),其长度可变,结构随通信域的不同而不同。
namelen表明了name的长度。
如果没有错误发生,bind()返回0。
否则返回值SOCKET_ERROR。
地址在建立套接字通信过程中起着重要作用,作为一个网络应用程序设计者对套接字地址结构必须有明确认识。
(3)建立套接字连接──connect()与accept()
这两个系统调用用于完成一个完整相关的建立,其中connect()用于建立连接。
无连接的套接字进程也可以调用connect(),但这时在进程之间没有实际的报文交换,调用将从本地操作系统直接返回。
这样做的优点是程序员不必为每一数据指定目的地址,而且如果收到的一个数据报,其目的端口未与任套接字建立“连接”,便能判断该端口不可操作。
而accept()用于使服务器等待来自某客户进程的实际连接。
connect()的调用格式如下:
intconnect(SOCKETs,conststructsockaddrFAR*name,intnamelen);
参数s是欲建立连接的本地套接字描述符。
参数name指出说明对方套接字地址结构的指针。
对方套接字地址长度由namelen说明。
如果没有错误发生,connect()返回0。
在面向连接的协议中,该调用导致本地系统和外部系统之间连接实际建立。
由于地址族总被包含在套接字地址结构的前两个字节中,并通过socket()调用与某个协议族相关。
因此bind()和connect()无须协议作为参数。
accept()的调用格式如下:
SOCKETaccept(SOCKETs,structsockaddrFAR*addr,intFAR*addrlen);
参数s为本地套接字描述符,在用做accept()调用的参数前应该先调用过listen()。
addr指向客户方套接字地址结构的指针,用来接收连接实体的地址。
addr的确切格式由套接字创建时建立的地址族决定。
addrlen为客户方套接字地址的长度(字节数)。
如果没有错误发生,accept()返回一个SOCKET类型的值,表示接收到的套接字的描述符。
否则返回值INVALID_SOCKET。
accept()用于面向连接服务器。
参数addr和addrlen存放客户方的地址信息。
调用前,参数addr指向一个初始值为空的地址结构,而addrlen的初始值为0;
调用accept()后,服务器等待从编号为s的套接字上接受客户连接请求,而连接请求是由客户方的connect()调用发出的。
当有连接请求到达时,accept()调用将请求连接队列上的第一个客户方套接字地址及长度放入addr和addrlen,并创建一个与s有相同特性的新套接字号。
新的套接字可用于处理服务器并发请求。
四个套接字系统调用,socket()、bind()、connect()、accept(),可以完成一个完全五元相关的建立。
socket()指定五元组中的协议元,它的用法与是否为客户或服务器、是否面向连接无关。
bind()指定五元组中的本地二元,即本地主机地址和端口号,其用法与是否面向连接有关:
在服务器方,无论是否面向连接,均要调用bind();
在客户方,若采用面向连接,则可以不调用bind(),而通过connect()自动完成。
若采用无连接,客户方必须使用bind()以获得一个唯一的地址。
以上讨论仅对客户/服务器模式而言,实际上套接字的使用是非常灵活的,唯一需遵循的原则是进程通信之前,必须建立完整的相关。
(4)监听连接──listen()
此调用用于面向连接服务器,表明它愿意接收连接。
listen()需在accept()之前调用,其调用格式如下:
intlisten(SOCKETs,intbacklog);
参数s标识一个本地已建立、尚未连接的套接字号,服务器愿意从它上面接收请求。
backlog表示请求连接队列的最大长度,用于限制排队请求的个数,目前允许的最大值为5。
如果没有错误发生,listen()返回0。
否则它返回SOCKET_ERROR。
listen()在执行调用过程中可为没有调用过bind()的套接字s完成所必须的连接,并建立长度为backlog的请求连接队列。
调用listen()是服务器接收一个连接请求的四个步骤中的第三步。
它在调用socket()分配一个流套接字,且调用bind()给s赋于一个名字之后调用,而且一定要在accept()之前调用。
(5)数据传输──send()与recv()
当一个连接建立以后,就可以传输数据了。
常用的系统调用有send()和recv()。
send()调用用于在参数s指定的已连接的数据报或流套接字上发送输出数据,格式如下:
intsend(SOCKETs,constcharFAR*buf,intlen,intflags);
参数s为已连接的本地套接字描述符。
buf指向存有发送数据的缓冲区的指针,其长度由len指定。
flags指定传输控制方式,如是否发送带外数据等。
如果没有错误发生,send()返回总共发送的字节数。
ecv()调用用于在参数s指定的已连接的数据报或流套接字上接收输入数据,格式如下:
intrecv(SOCKETs,charFAR*buf,intlen,intflags);
参数s为已连接的套接字描述符。
buf指向接收输入数据缓冲区的指针,其长度由len指定。
flags指定传输控制方式,如是否接收带外数据等。
如果没有错误发生,recv()返回总共接收的字节数。
如果连接被关闭,返回0。
否则它返回SOCKET_ERROR。
(6)输入/输出多路复用──select()
select()调用用来检测一个或多个套接字的状态。
对每一个套接字来说,这个调用可以请求读、写或错误状态方面的信息。
请求给定状态的套接字集合由一个fd_set结构指示。
在返回时,此结构被更新,以反映那些满足特定条件的套接字的子集,同时,select()调用返回满足条件的套接字的数目,其调用格式如下:
intselect(intnfds,fd_setFAR*readfds,fd_setFAR*writefds,
fd_setFAR*exceptfds,conststructtimevalFAR*timeout);
参数nfds指明被检查的套接字描述符的值域,此变量一般被忽略。
参数readfds指向要做读检测的套接字描述符集合的指针,调用者希望从中读取数据。
参数writefds指向要做写检测的套接字描述符集合的指针。
exceptfds指向要检测是否出错的套接字描述符集合的指针。
timeout指向select()函数等待的最大时间,如果设为NULL则为阻塞操作。
select()返回包含在fd_set结构中已准备好的套接字描述符的总数目,或者是发生错误则返回SOCKET_ERROR。
(7)关闭套接字──closesocket()
closesocket()关闭套接字s,并释放分配给该套接字的资源;
如果s涉及一个打开的TCP连接,则该连接被释放。
closesocket()的调用格式如下:
BOOLclosesocket(SOCKETs);
参数s待关闭的套接字描述符。
如果没有错误发生,closesocket()返回0。
2、用于无连接协议(如UDP)的SOCKET系统调用流程框图:
3、用于面向连接协议(如TCP)的SOCKET系统调用流程框图:
四、实验步骤
练习一:
使用UDP协议的无连接客户-服务员程序设计。
根据实验原理中介绍的内容,设计一个无连接的客户-服务员系统,实现二者之间的数
据传递。
下面是一个简单的UDP客户-服务员程序的实例,作为参考。
说明:
下述服务员程序已经在服务器端运行,在仿真机端仅需编写相应的客户程序并运行。
#include<
stdio.h>
winsock.h>
#defineSERV_UDP_PORT6000/*服务员进程端口号,视具体情况而定*/
#defineSERV_HOST_ADDR"
10.60.46.58"
/*服务员地址,视具体情况而定*/
/*宏定义用来打印错误消息*/
#definePRINTERROR(s)\
fprintf(stderr,"
\n%:
%d\n"
s,WSAGetLastError())
////////////////////////////////////////////////////////////
//数据报通信的服务员端子程序//
voidDatagramServer(shortnPort)
{
SOCKETtheSocket;
/*创建一个数据报类型的socket*/
theSocket=socket(AF_INET,//地址族
SOCK_DGRAM,//socket类型
IPPROTO_UDP);
//协议类型:
UDP
/*错误处理*/
if(theSocket==INVALID_SOCKET)
PRINTERROR("
socket()"
);
return;
/*填写服务员地址结构*/
SOCKADDR_INsaServer;
saServer.sin_family=AF_INET;
saServer.sin_addr.s_addr=INADDR_ANY;
//由WinSock指定地址
saServer.sin_port=htons(nPort);
//服务员进程端口号
/*将服务员地址与已创建的socket绑定*/
intnRet;
nRet=bind(theSocket,//Socket描述符
(LPSOCKADDR)&
saServer,//服务员地址
sizeof(structsockaddr)//地址长度
);
/*错误处理*/
if(nRet==SOCKET_ERROR)
bind()"
closesocket(theSocket);
/*等待来自客户端的数据*/
SOCKADDR_INsaClient;
charszBuf[1024];
intnLen;
while
(1)
/*准备接收数据*/
memset(szBuf,0,sizeof(szBuf));
nRet=recvfrom(theSocket,//已绑定的socket
szBuf,//接收缓冲区
sizeof(szBuf),//缓冲区大小
0,//Flags
saClient,//接收客户端地址的缓冲区
&
nLen);
//地址缓冲区的长度
/*打印接收到的信息*/
printf("
\nDatareceived:
%s"
szBuf);
/*发送数据给客户端*/
strcpy(szBuf,"
FromtheServer"
sendto(theSocket,//已绑定的socket
szBuf,//发送缓冲区
strlen(szBuf),//发送数据的长度
saClient,//目的地址
nLen);
//地址长度
//数据报服务员端主程序//
voidmain()
WORDwVersionRequested=MAKEWORD(1,1);
WSADATAwsaData;
shortnPort;
nPort=SERV_UDP_PORT;
/*初始化Winsock*/
nRet=WSAStartup(wVersionRequested,&
wsaData);
if(wsaData.wVersion!
=wVersionRequested)
\nWrongversion\n"
/*调用数据服务员子程序*/
DatagramServer(nPort);
/*结束WinSock*/
WSACleanup();
上述服务员程序已经在服务器端运行,请学生认真阅读分析后,然后根据实验原理二
中介绍的内容,在仿真机端编写相应的无连接的客户端程序并运行。
从而实现客户和服务
器间的数据传输。
在仿真机一端运行客户端进程,在监控机端捕获数据并进行分析。
练习二:
使用TCP协议的面向连接的客户-服务员程序设计。
根据实验原理中介绍的内容,设计一个面向连接的客户-服务员系统,实现二者之间的
数据传递。
下面是一个简单的TCP客户-服务员程序的服务员程序:
面向连接的服务员程序:
PROCESS.H>
windows.h>
sys/types.h>
fcntl.h>
wsipx.h>
wsnwlink.h>
#defineSERV_TCP_PORT6000/*服务员进程端口号,视具体情况而定*/
10.60.46.40"
/*服务员IP,视具体情况而定*/
intsockfd;
//////////////////////////////////////////////////////////////////////////
//线程用来处理客户端的请求//
//服务员主进程每与某客户端建立一个连接之后,便启动一个新的线程来处理接下//
//客户端的请求,参数为服务员与该客户端的连接点:
socket//
DWORDClientThread(void*pVoid)
/*接收来自客户端的数据信息*/
nRet=recv((SOCKET)pVoid,//与客户端连接的socket
sizeof(szBuf),//缓冲区长度
0);
//Flags
if(nRet==INVALID_SOCKET)
recv()"
closesocket(sockfd);
closesocket((SOCKET)pVoid);
return0;
/*显示接收到的数据*/
%s\n"
//发送内容
nRet=send((SOCKET)pVoid,//与客户端连接的socket
szBuf,//数据缓冲区
strlen(szBuf),//数据长度
/*结束连接,释放socket*/
//////////////////////////////////////////////////////////////
//服务员主程序:
//
//在一个众所周知的端口上等待客户的连接请求//
//有请求到来时建立与客户端的连接,并启动一个线程处理该请求//
intmain()
intclilen;
intpHandle=-1;
structsockaddr_inserv_addr;
SOCKETsocketClient;
DWORDThreadAddr;
HANDLEdwClientThread;
SOCKADDR_INSockAddr;
/*初始化WinsockAPI,即连接Winsock库*/
WORDwVersionRequested=MAKEWORD(1,1);
if(WSAStartup(wVersionRequested,&
wsaData)){
WSAStartupfailed%s\n"
WSAGetLastError());
return-1;
/*打开一个TCPSOCKET*/
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<
0)
se
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- UDPTCP 客户 服务员 程序设计