计算机网络课上机题.docx
- 文档编号:25876581
- 上传时间:2023-06-16
- 格式:DOCX
- 页数:26
- 大小:27.38KB
计算机网络课上机题.docx
《计算机网络课上机题.docx》由会员分享,可在线阅读,更多相关《计算机网络课上机题.docx(26页珍藏版)》请在冰豆网上搜索。
计算机网络课上机题
计算机网络课上机题
一、实验目的
BSDsocket目前已经被广泛移植到各个平台,因此熟悉了BSDsocket的编程界面,对以后的学习、工作都有很重要的现实意义。
了解BSDsocket编程界面,熟悉socket相关的各种API的使用,如socket,bind,listen,accept,connect,send,recv,sendto,recvfrom,htonl,ntohl,htons,ntohs等。
了解阻塞式IO、非阻塞式IO概念与控制。
二、实验基础
每个socket的应用,通常都有如下的API的使用:
socket用于生成一个套节字
accept接受一个连接请求,用于服务器端的编程
connect发起一个连接请求,用于客户端的编程
send/sendto发送信息
recv/recvfrom接收信息
select多路复用调用
bind将主机的地址/端口信息与某个socket相关联
listen进入监听状态
close关闭一个socket
shutdown断开连接
fcntl设置socket的选项
htons主机序到网络序的短整型
ntohs网络序到主机序的短整型
通常的服务器端的编程:
通常的客户端编程
socketsocket
bind
listen
acceptconnect
send/recvsend/recv
shutdownshutdown
closeclose
IPv6是对现有的Ipv4的扩展,在编程界面上,都和v4的类似,只是地址部分有变化。
三、编程上机题目(注意:
请用C语言编程)
1.写简单的socket应用程序,应用的内容和形式可以自己决定。
可以是基于client/server结构的,也可以是对等结构的。
目的是熟悉基本的socket应用程序的编写。
基本要求:
使用基本的API函数。
服务器端至少能够支持一个客户,客户端和服务器端能够互相发送/接收信息。
可以选择udp或者tcp协议。
例1:
简单的回显程序,即客户端输入什么,服务器端能够回送什么
例2:
两个人的聊天程序,即你一言,我一语的那种。
2.套接字Socket应用。
熟悉unix环境下socket编程的几种编程的使用模式,阻塞式IO的多客户端支持,非阻塞IO的使用等。
基本要求:
使用select来实现多个客户端的多路复用,至少支持4个以上的客户端。
可以结合题目1一起做。
例1:
可以写一个聊天室,功能能够实现多个人同时登录,进行聊天。
登录时提示输入昵称,不允许重复的登录,进入聊天室以后可以说话,每个里面的人都能看到。
例2:
可以写一个HTTP的Proxy,功能是实现简单的Proxy的功能,可以通过你的应用程序,进行HTTP的访问。
注意支持多个客户端。
3.编写简单多播应用程序。
应用的环境不限。
可以是视频流或者音频流或者其他形式的内容。
基本的要求:
使用基本的API函数。
客户端和服务器端之间的交互可以使用如下的结构:
server<-文件应用程序<-client
|____________________网络______________________|
文件可以是视频/音频流。
至少能有两个以上的客户端能够接收到同步的信息并且播放。
例1:
音频多播
可以以音频文件为输入流,循环地通过服务程序播送;客户端从网络接收,并能够传递给播放软件。
例2:
视频多播
同上,以视频文件为输入流。
四、参考书籍
Unix网络编程电子工业出版社
Linux网络编程清华大学出版社
Windows网络编程机械工业出版社
ftp:
//202.38.75.11/EBooks/Unix_Programming/Windows网络编程技术
特别致谢
向计算机科学技术系2000级研究生杨琛同学表示特别感谢。
附录:
1.简单的说明
linux下编写socket的应用程序比较简单,如果有不太清楚的调用,可以直接通过mansocket等的使用来观察应该包含的头文件,函数的原型,以及正常时应该的返回值。
编译通常的程序可以使用(g)ccsource.c–ooutfile来进行,如果是c++的程序,g++source.c–ooutfile
运行:
$./outfile回车
后台执行$./outfile&回车
Windows下面的编程稍微麻烦一点,需要安装MSDN,里面也有详细的每个函数的说明。
在PlatformSDK:
WinSock的部分。
要编写Winsock的应用程序应该包含头文件winsock.h。
然后在工程的设置的Link里面加上winsock32.lib。
或者在程序中写上
#pragmacomment(lib,”winsock32”)
并且,每个Winsock的应用程序都要进行Winsock的初始化,WSAStartup/WSACleanup。
具体的可以参考202.38.75.11上的电子书。
2.部分中文材料:
TCP/IP编程接口介绍
Linux/Unix:
Socket函数库
LinuxSocket函数库是从Berkeley大学开发的BSDUNIX系统中移植过来的。
BSDSocket接口是在众多Unix系统中被广泛支持的TCP/IP通信接口,Linux下的Socket程序设计,除了微小的差别之外,也适用于大多数其它Unix系统。
Socket的使用和文件操作比较类似。
如同文件的读、写、打开、关闭等操作一样,TCP/IP网络通信同样也有这些操作,不过它使用的接口不是文件描述符或者FILE*,而是一个称做Socket的描述符。
类似于文件操作,对于Socket,也通过读、写、打开、关闭操作来进行网络数据传送。
同时,还有一些辅助的函数,如域名/IP地址查询、Socket功能设置等。
以下是函数分类介绍(此介绍选自Linuxmanpage,不当之处,请参阅原文):
1.Socket操作:
Socket():
分配Socket
#include
#include
intsocket(intdomain,inttype,intprotocol);
socket()函数分配一个Socket句柄,用于指定特定网络下、使用特定的协议和数据传送方式进行通信。
Socket接口是不仅仅局限于TCP/IP的,但是由于TCP/IP的广泛使用,它们几乎被完全等同起来了。
Socket句柄分配以后,如果要开始TCP通信,还需要建立连接。
根据需要,可以主动地建立连接(通过connect())和被动地等待对方建立连接(通过listen()),在连接建立后才能使用读写操作通过网络连接进行数据交换。
参数说明:
domain:
domain参数选择通信中使用的协议族,也就是网络的类型,可以是以下之一:
AF_UNIX(UNIX内部协议)
AF_INET(ARPAInternet协议,也就是TCP/IP协议族,亦即我们实验中所使用的)
AF_ISO(ISO协议)
AF_NS(XeroxNetworkSystems协议)
AF_IMPLINK(IMP"hostatIMP"linklayer)
type:
数据传送的方式,可以是以下之一:
SOCK_STREAM:
保证顺序的、可靠传送的双向字节数据流,最为常用,也是TCP连接所使用的方式。
SOCK_DGRAM:
无连接的、不保证可靠的、固定长度(通常很小)的消息传送。
SOCK_SEQPACKET:
顺序的、可靠的双向固定长度的数据包传送,只用于AF_NS类型的网络中。
SOCK_RAW:
原始的数据传送,适用于系统内部专用的网络协议和接口,和SOCK_RDM一样,只能由超级用户使用。
SOCK_RDM:
可靠的数据报传送,未实现。
Protocol:
protocol参数指定通信中使用的协议。
在给定Socket的协议族和传送类型之后,一般情况下所使用的协议也就固定下来,如下表所示,此时protocol参数可使用缺省值’0’;但如果还有多个协议供选择,则必须使用protocol参数来标识。
协议族(仅考虑IP协议族)
传送类型
protocol参数常量(/usr/include/linux/in.h)
协议类型
AF_INET
SOCK_STREAM
IPPROTO_TCP
TCP
SOCK_DGRAM
IPPROTO_UDP
UDP
SOCK_RAW
IPPROTO_ICMP
ICMP
SOCK_RAW
IPRROTO_RAW
(raw)
返回值:
正常执行时,返回Socket描述符;否则,返回-1,错误状态在全局变量errno中。
close():
关闭Socket
#include
intclose(intfd);
Socket和文件描述符的关闭操作都是使用这个函数。
参数说明:
fd:
Socket描述符。
返回值:
正常时返回0,-1表示出错。
bind():
给Socket指定本地地址
#include
#include
intbind(intsockfd,structsockaddr*my_addr,intaddrlen);
bind函数给已经打开的Socket指定本地地址。
这个函数的使用有以下两种情况:
如果此Socket是面向连接的,而且此Socket在连接建立过程中处于被动的地位,
即己方程序使用listen函数等待对方建立连接,对方用connect函数来向此Socket建立连接,这种情况下,必须用bind给此Socket设定本地地址。
在己方使用listen函数时,除指定Socket描述符之外,该Socket必须已经用bind函数设定好了本地地址(包括IP地址和端口号),这样,系统在收到建立连接的网络请求时,才能根据请求的目的地址,识别是通向哪个Socket的连接,从而己方才能用此Socket接收到发给此Socket地址的数据包。
不指定Socket的本地地址,就无法将此Socket用于连接建立和数据接收。
如果此Socket用于无连接的情形,同样也要求给该Socket设定本地地址,这样,
以后系统从网络中接收到数据后,才知道该送给哪个Socket及其相对应的进程。
参数说明:
sockfd:
Socket描述符。
Addrlen:
my_addr结构的长度。
my_addr:
用于侦听连接请求的本地地址。
structsockaddr是一个通用型的结构,不仅包含TCP/IP协议的情况,同时也是为了适合于其它网络,如AF_NS。
由于它的这种通用性,它只是定义了一个一般意义上的存储空间,如/usr/include/linux/socket.h中所示:
structsockaddr
{
unsignedshortsa_family;/*addressfamily,AF_xxx*/
charsa_data[14];/*14bytesofprotocoladdress*/
};
当使用TCP/IP协议(即Internet协议)时,可用如下的struct等价地代替structsockaddr(/usr/include/linux/in.h):
#define__SOCK_SIZE__16/*sizeof(structsockaddr)*/
structsockaddr_in{
shortintsin_family;/*Addressfamily*/
unsignedshortintsin_port;/*Portnumber*/
structin_addrsin_addr;/*Internetaddress*/
/*Padtosizeof`structsockaddr'.*/
unsignedchar__pad[__SOCK_SIZE__-sizeof(shortint)-
sizeof(unsignedshortint)-sizeof(structin_addr)];
};
在Socket程序中,等待建立连接一方的准备过程请参见编程实例,以及listen()、accept()的说明。
返回值:
正常时返回0,否则返回-1,同时errno是系统错误码。
listen():
准备接受连接请求。
#include
intlisten(ints,intbacklog);
在用bind()给一个Socket设定本地地址之后,就可以将这个Socket用于接受连接请求,即listen()。
调用listen()之后,系统将给此Socket配备一个连接请求的队列,暂存系统接收到的、申请向此Socket建立连接的请求,等待用户程序用accept()正式接受该请求。
队列长度,就由backlog参数指定。
如下面的简图所示:
通信己方Me
通信对方
Socket_Me
PeerSockets
连接请求暂存队列
[0]<--连接建立请求1
<--connect()
Socket_peer_1
[1]<--连接建立请求2
<--connect()
Socket_peer_2
……
……
……
[backlog-1]<--连接建立请求n
<--connect()
Socket_peer_n
如果短时间内向己方建立连接的请求过多,己方来不及处理,那么排在backlog之后的请求将被系统拒绝。
因此,backlog参数实际上规定了己方程序能够容许的连接建立处理速度。
至于己方程序使用此Socket(及其指定的本地地址)实际建立连接的个数,由己方程序调用accept()的次数来决定,参见accept()的说明。
参数说明:
s:
Socket描述符。
Backlog:
连接请求暂存队列长度。
返回值:
正常时返回0;否则返回-1,同时errno是系统错误码。
accept:
接受指定Socket上的连接请求
#include
#include
intaccept(ints,structsockaddr*addr,int*addrlen);
在调用listen()之后,系统就在Socket的连接请求暂存队列里存放每一个向该Socket(及其本地地址)建立的连接请求。
accept()函数的作用就是,从该暂存队列中取出一个连接请求,用该Socket的数据,创建一个新的Socket:
Socket_New,并为它分配一个文件描述符。
Socket_New即标识了此次建立的连接,可被己方用来向连接的另一方发送和接收数据(write/read,send/recv)。
同时,原Socket仍然保持打开状态不变,继续用于等待网络连接请求。
如果该Socket的暂存队列中没有待处理的连接请求,根据Socket的特征选项(是否non_blocking),accept()函数将选择两种方式:
如果该Socket不是non_blocking型的,accept()将一直等待,直到收到一个连接请求后才返回;如果该Socket是non_blocking型的,那么accept()将立即返回,但如果没有连接请求,只返回错误信息,不创建新的Socket_New。
accept()返回后,如果创建了新的Socket_New来标识新建立的连接,那么参数addr指定的结构里面将会有对方的地址信息,addrlen是地址信息的长度。
关于accept()的进一步信息,如:
如何检测某Socket有无待处理的连接请求、如何在使用accept()接受连接请求之前先获取连接对方的地址、如何根据获取的对方地址信息拒绝该连接请求等,请参阅Linuxmanual,此处不再累述。
参数说明:
s:
Socket描述符。
addr:
accept()接受连接后,在addr指向的结构中存放对方的地址信息。
如果是AF_INETSocket,该地址信息就是对方的IP地址和端口号。
addrlen:
在调用accept()之前,*addrlen必须被设置为addr数据结构的合法长度。
在accept()返回之后,*addrlen中是对方地址信息的长度。
返回值:
如果正常创建了一个新的连接,那么返回非负的整数:
即新连接的Socket描述符(注意,用于等待连接请求的原Socket保持打开状态不变,可用于接收新的连接请求。
);否则,返回-1,errno是系统错误码。
connect:
建立连接
#include
#include
intconnect(intsockfd,structsockaddr*serv_addr,intaddrlen);
前面提到的函数,如bind、listen、connect等,都是用于被动地等待对方建立连接时需要使用的,而connect()函数,则是主动地向对方建立连接时使用的。
connect()使用一个事先打开的Socket,和目的方(即通信对方,或称服务器一方)地址信息,向对方发出连接建立请求。
一个完整的Socket通信发起过程可简单地图示为:
主动发起方(客户方)
被动接受方(服务方)
listen(sock_w);等待连接建立请求
connect(sock_s)
{
发送连接建立请求
->
<-
sock_d=accept();接受连接建立请求
发送应答
收到连接建立应答
}
此时,在sock_s和sock_d之间,一个连接就建立完毕。
如果是SOCK_STREAM型的Socket,通常只用connect()建立一个正常的连接。
但如果是SOCK_DGRAM型的Socket,connect()函数并不象上图中那样向目的方发出连接建立请求,而只是简单地用给出的地址设置该Socket的目的地址,以后该Socket的无连接数据报就发往该目的地址。
因此,对于SOCK_DGRAM型的Socket,可以多次调用connect()来改变该Socket的目的地址。
SOCK_DGRAM型的Socket与本实验关系不大,故不再详述。
参数说明:
sockfd:
Socket描述符。
serv_addr:
通信目的方的地址。
其格式参见bind()的说明。
Addrlen:
目的地址长度。
返回值:
连接正常建立时返回0;否则,返回-1,系统错误码在errno中。
send/recv:
用Socket发送和接收数据
#include
#include
intsend(ints,constvoid*msg,intlen,unsignedintflags);
intsendto(ints,constvoid*msg,intlen,unsignedintflags,
conststructsockaddr*to,inttolen);
intrecv(ints,void*buf,intlen,unsignedintflags);
intrecvfrom(ints,void*buf,intlen,unsignedintflags,structsockaddr*from,int*fromlen);
在连接建立完成后,通信双方就可以使用以上这些函数来进行数据的发送和接收操作。
其中,send和recv用于连接建立以后的发送和接收;sendto和recvfrom用于非连接的协议。
对于非non_blocking型的Socket,send将等待数据发送完后才返回;对于non_blocking型的Socket,send将立即返回,用户程序需要用select()函数决定网络发送是否结束。
类似地,对于非non_blocking型的Socket,若系统没有收到任何数据,recv将等待接收数据到达后才返回;对于non_blocking型的Socket,recv将立即返回,并返回错误信息或者接收到的数据字节数。
sendto和recvfrom因为是非连接型的发送和接收,必须在参数中给出目的地址或者存放源地址的空间。
参数说明:
s:
Socket描述符;
msg,buf:
存放接收或者发送数据的存储空间;
len:
接收或者发送数据的字节数;
to,from:
sendto和recvfrom所使用的,目的方地址和存放源地址的空间;
tolen,fromlen:
目的地址和源地址空间大小。
flag:
通常设为0,详细说明请参见LinuxManual。
返回值:
send/sendto返回实际发送的数据字节数,或者-1,表示出错;
recv/recvfrom返回实际接收到的数据字节数,或者-1,表示出错。
read/write:
用系统文件操作进行Socket通信
#include
ssize_tread(intfd,void*buf,size_tcount);
ssize_twrite(intfd,constvoid*buf,size_tcount);
在连接建立完成后,对于连接建立过程中被动的一方,在accept()正常返回后,它返回一个新的Socket,并且为该Socket分配了一个文件描述符;对于连接请求发起方,connect()正常返回后,相应的Socket中也包含有已分配的文件描述符。
因此,可以使用标准的Unix文件读写函数read()/write()来进行Socket通信。
要注意的是,由于网络数据和磁盘文件不一样,不是已经准备好的,因此,每次读写操作不一定能传送完指定长度的数据,需要由程序反复进行剩余部分的传送。
另外,文件描述符是较底层的文件操作参数,不同于C语言中常用的FILE*。
FILE*是使用fread/fwrite函数来进行读写操作的。
参数说明:
fd:
文件或者Socket描述符。
buf:
数据缓冲区。
count:
数据字节数。
返回值:
正常时,返回所读写的字节数(注意,可能小于count参数指定的数目);否则,返回-1,errno是系统错误码。
getsockopt/setsockopt:
获取、设置Socket特征选项。
#include
#include
intgetsockopt(ints,intlevel,intoptname,void*optval,int*optlen);
intsetsockopt(ints,intlevel,intoptname
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 计算机网络 上机