实验指导书实验07 TCPIP Socket编程.docx
- 文档编号:16373315
- 上传时间:2023-07-13
- 格式:DOCX
- 页数:13
- 大小:55.77KB
实验指导书实验07 TCPIP Socket编程.docx
《实验指导书实验07 TCPIP Socket编程.docx》由会员分享,可在线阅读,更多相关《实验指导书实验07 TCPIP Socket编程.docx(13页珍藏版)》请在冰点文库上搜索。
实验指导书实验07TCPIPSocket编程
实验七TCP/IPSocket编程
一、实验题目
TCP/IPSocket编程
二、实验课时
6课时。
三、实验目的
1、进一步掌握TCP及UDP协议的工作原理
2、掌握socket编程的基本方法
3、学习应用C语言与WinSock2进行简单的面向连接或无连接的网络程序设计,实现网络数据传输。
或使用java语言编程实现。
四、实验内容和要求
环境:
WindowsXP,c++或java语言实现
内容和方法:
(1)分别编写基于TCP的socket程序服务端和客户端,要求客户端能发送消息到服务端,服务端再把此消息返回给客户端。
(2)在上述程序的基础上,实现客户端和服务端间的简易聊天功能,即服务端和客户端能依次从键盘输入文字信息并发送(要求在两台不同的电脑上进行)。
(3)改用UDP实现此程序的功能。
(4)使用netstat命令观察程序运行前后的端口变化情况并记录下来。
以下内容可选做(注:
可只用命令行字符界面实现):
(5)实现服务端能同时连接多个客户端
(6)服务端实现消息转发到任意一个客户端,设计通信协议,使得任意一个客户端都能通过服务端与另外任意一个联网客户端进行聊天。
(7)实现任意两个用户之间的文件传输。
附:
实验原理
1.Socket
Socket,中文翻译成“套接字”。
Socket是TCP/IP应用程序(比如InternetExplorer、CuteFTP)同底层的通信驱动程序(比如MODEM驱动程序)之间运行的TCP/IP驱动程序。
Socket扮演的角色就是将应用程序同具体的TCP/IP协议隔离开来,使得应用程序不必了解TCP/IP的细节,就能实现数据传输。
有了Socket,我们就可以在Internet上的两台计算机间传递任何数据了。
高层协议,比如HTTP、FTP,都要通过TCP/IP提供的网络传输能力传输数据。
2.Winsock
WindowsSocket,简称Winsock,WINSOCK是在Windows进行网络通信编程的API接口。
编制底层网络应用程序通常要借助于网络数据通信编程接口,而在不同的操作系统中所提供的网络编程接口是有所不同的,如在MicrosoftWindows环境下的网络编程接口就是Windows套接字(WindowsSocket,简称Winsock)。
3.关于使用套接字编程的一些基本概念
(a)TCP/IP协议的地址结构为:
structsockaddr_in{
shortsin_family;/*AF_INET*/
u_shortsin_port;/*16位端口号,网络字节顺序*/
structin_addrsin_addr;/*32位IP地址,网络字节顺序*/
charsin_zero[8];/*保留*/
}
(b)套接字类型
TCP/IP的socket提供下列三种类型套接字。
流式套接字(SOCK_STREAM)
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复地发送,且按发送顺序接收。
内设流量控制,避免数据流超限;数据被看作是字节流,无长度限制。
文件传送协议(FTP)即使用流式套接字。
数据报式套接字(SOCK_DGRAM)
提供了一个无连接服务。
数据包以独立包形式被发送,不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。
网络文件系统(NFS)使用数据报式套接字。
原始式套接字(SOCK_RAW)
该接口允许对较低层协议,如IP、ICMP直接访问。
常用于检验新的协议实现或访问现有服务中配置的新设备。
(c)基本套接字系统调用
为了更好地说明套接字编程原理,下面给出几个基本套接字系统调用说明。
(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,使用默认的连接模式。
根据这三个参数建立一个套接字,并将相应的资源分配给它,同时返回一个整型套接字号。
例如:
首先我们建立一个m_socket的SOCKET句柄,接着调用socket()函数,函数返回值保存在m_socket中.我们使用AF_INET,SOCK_STREAM,IPPROTO_TCP三个参数.第一个表示地址族,AF_INET表示TCP/IP族,第二个表示服务类型,在WINSOCK2中,SOCKET支持以下三种类型:
SOCK_STREAM 流式套接字
SOCK_DGRAM 数据报套接字
SOCK_RAW 原始套接字
第三个参数表示协议:
IPPROTO_UDP UDP协议 用于无连接数据报套接字
IPPROTO_TCP TCP协议 用于流式套接字
IPPROTO_ICMP ICMP协议用于原始套接字
m_socket=socket(AF_INFE,SOCK_STREAM,IPPROTO_TCP); //创建TCP协议
(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_ERROR。
在面向连接的协议中,该调用导致本地系统和外部系统之间连接实际建立。
由于地址族总被包含在套接字地址结构的前两个字节中,并通过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()指定本地主机地址和端口号,其用法与是否面向连接有关:
在服务器方,无论是否面向连接,均要调用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()、sendto()与recv()、recvfrom()
当一个连接建立以后,就可以传输数据了。
常用的系统调用有send()和recv()。
send()调用用于在参数s指定的已连接的数据报或流套接字上发送输出数据,格式如下:
intsend(SOCKETs,constcharFAR*buf,intlen,intflags);
参数s为已连接的本地套接字描述符。
buf指向存有发送数据的缓冲区的指针,其长度由len指定。
flags指定传输控制方式,如是否发送带外数据等。
如果没有错误发生,send()返回总共发送的字节数。
否则它返回SOCKET_ERROR。
recv()调用用于在参数s指定的已连接的数据报或流套接字上接收输入数据,格式如下:
intrecv(SOCKETs,charFAR*buf,intlen,intflags);
参数s为已连接的套接字描述符。
buf指向接收输入数据缓冲区的指针,其长度由len指定。
flags指定传输控制方式,如是否接收带外数据等。
如果没有错误发生,recv()返回总共接收的字节数。
如果连接被关闭,返回0。
否则它返回SOCKET_ERROR。
虽然基于TCP/IP连接协议(流套接字)的服务是设计客户机/服务器应用程序时的主流标准,但有些服务也是可以通过无连接协议(数据报套接字)提供的。
先介绍一下TCPsocket与UDPsocket在传送数据时的特性:
Stream(TCP)Socket提供双向、可靠、有次序、不重复的资料传送。
Datagram(UDP)Socket虽然提供双向的通信,但没有可靠、有次序、不重复的保证,所以UDP传送数据可能会收到无次序、重复的资料,甚至资料在传输过程中出现遗漏。
由于UDPSocket在传送资料时,并不保证资料能完整地送达对方,所以绝大多数应用程序都是采用TCP处理Socket,以保证资料的正确性。
一般情况下TCPSocket的数据发送和接收是调用send()及recv()这两个函数来达成,而UDPSocket则是用sendto()及recvfrom()这两个函数,这两个函数调用成功发挥发送或接收的资料的长度,否则返回SOCKET_ERROR。
(6)关闭套接字──closesocket()
closesocket()关闭套接字s,并释放分配给该套接字的资源;如果s涉及一个打开的TCP连接,则该连接被释放。
closesocket()的调用格式如下:
BOOLclosesocket(SOCKETs);
参数s待关闭的套接字描述符。
如果没有错误发生,closesocket()返回0。
否则返回值SOCKET_ERROR。
4.用于无连接协议(如UDP)的SOCKET系统调用流程框图:
5.用于面向连接协议(如TCP)的SOCKET系统调用流程框图:
6.简单的TCP通信程序示例
在WIN32平台上的WINSOCK编程都要经过下列步骤:
定义变量->获得WINDOCK版本->加载WINSOCK库->初始化->创建套接字->设置套接字选项->关闭套接字->卸载WINSOCK库->释放资源
下面介绍WINSOCK C/S的建立过程:
服务器 客户端
________________________________________________
1 初始化WSA 1 初始化WSA
____________________________________________________
2 建立一个SOCKET 2 建立一个SOCKET
_____________________________________________________
3 绑定SOCKET 3 连接到服务器
_____________________________________________________
4 在指定的端口监听 4 发送和接受数据
_____________________________________________________
5 接受一个连接 5 断开连接
______________________________________________________
6 发送和接受数据
___________________________________________________
7 断开连接
__________________________________________________
在VC中进行WINSOCK编程时,需要引入如下两个库文件:
WINSOCK.H(这个是WINSOCK API的头文件,WIN2K以上支持WINSOCK2,所以可以用WINSOCK2.H);Ws2_32.lib(WINSOCK API连接库文件).
使用方式如下:
#include
#pragma comment(lib,"ws2_32.lib")
在所有WindowsSockets函数中,只有启动函数WSAStartup()和终止函数WSACleanup()是必须使用的,这两个函数必须成对使用。
启动函数必须是第一个使用的函数,而且它允许指定WindowsSocketsAPI的版本,并获得SOCKETS的特定的一些技术细节。
本结构如下:
intPASCALFARWSAStartup(WORDwVersionRequested,LPWSADATAlpWSAData);
lpWSAData用来存储系统传回的关于WinSocket的资料
结束服务器和客户端的通信连接是很简单的,这一过程可以由服务器或客户机的任一端启动,只要调用closesocket()就可以了,而要关闭Server端监听状态的socket,同样也是利用此函数。
另外,与程序启动时调用WSAStartup()憨数相对应,程序结束前,需要调用WSACleanup()来通知WinsockStack释放Socket所占用的资源。
这两个函数都是调用成功返回0,否则返回SOCKET_ERROR。
例子:
服务端:
(1)打开vc++6.0,File-》new-》Projects-》Win32ConsoleApplication,输入Projectname,例如SimpleTCP_s,选择location后单击OK,选择simpleapplication,单击ok。
(2)打开SimpleTCP_s.cpp,输入如下内容:
#include"stdafx.h"
#include
#include
//可以用WINSOCK2.H);
#pragmacomment(lib,"WS2_32.lib")//Ws2_32.lib(WINSOCKAPI连接库文件).
#defineBUF_SIZE1024
intmain(intargc,char*argv[])
{
WSADATAwsaData;
SOCKETsocketL;//socketforlistening
SOCKETsocketC;//socketforCommunication
SOCKADDR_INserverAddr;
intnRet=-1;
charrecvbuf[BUF_SIZE];
if(WSAStartup(MAKEWORD(2,2),&wsaData)!
=0)
{
printf("WSAStartupfailed!
\n");
return1;
}
socketL=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
serverAddr.sin_family=AF_INET;
serverAddr.sin_port=htons(5678);
serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);
bind(socketL,(SOCKADDR*)&serverAddr,sizeof(serverAddr));
listen(socketL,5);
socketC=accept(socketL,NULL,NULL);
if(socketC!
=INVALID_SOCKET)
{
nRet=recv(socketC,recvbuf,sizeof(recvbuf),0);
if(nRet>0)
printf("%s",recvbuf);
}
closesocket(socketC);
closesocket(socketL);
WSACleanup();
printf("请按回车键关闭");
getchar();
return0;
}
(3)编译工程
客户端:
(1)和服务端一样操作,建立SimpleTCP_c工程。
(2)打开SimpleTCP_c.cpp,输入如下内容:
#include"stdafx.h"
#include
#include
#pragmacomment(lib,"WS2_32.lib")
#defineBUF_SIZE1024
intmain(intargc,char*argv[])
{
WSADATAwsaData;
SOCKADDR_INserverAddr;
SOCKETsocketC;
charsendbuf[BUF_SIZE]="HelloTCPWorld!
";
if(WSAStartup(MAKEWORD(2,2),&wsaData)!
=0)
{
printf("WSAStartupfailed!
\n");
return1;
}
socketC=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
serverAddr.sin_family=AF_INET;
serverAddr.sin_port=htons(5678);
serverAddr.sin_addr.s_addr=inet_addr("127.0.0.1");
connect(socketC,(SOCKADDR*)&serverAddr,sizeof(serverAddr));
send(socketC,sendbuf,sizeof(sendbuf),0);
closesocket(socketC);
WSACleanup();
printf("请按回车键关闭");
getchar();
return0;
}
(3)编译工程
分别运行服务端SimpleTCP_s.exe和客户端SimpleTCP_c.exe,则在服务端显示"HelloTCPWorld!
"。
(注:
文档可能无法思考全面,请浏览后下载,供参考。
可复制、编制,期待你的好评与关注)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验指导书实验07 TCPIP Socket编程 实验 指导书 07 Socket 编程