线
订
装
线
订
装
西 安 电 子 科 技 大 学
考试时间 120 分钟
试 题
题号
一 二 三 四 五 六
总分
分数
1.考试形式:闭卷 开卷□ ;2.本试卷共六大题,满分 100 分;
3.考试日期: 年 月 日;(答题内容请写在装订线外)
说明:
1.每道题在答题时分为二个部分:1)问题分析和方案设计;2)编程。
2.网络层协议使用 ipv4。
3.为减少手写代码量:
1)不用写头文件,bind()、connect()、accept()函数不用写参数;
2)不用考虑出现中断(EINTR)的情况,也不用考虑 read()返回值为 0
的情况;
3)给 sockaddr 或 sockaddr_in 填写内容时,可用 SET_ADDR_PORT(单播)
或 SET_ADDR_PORT_255(广播)代替;从磁盘上读取文件可用
int len=READ_FILE(char* buf)代替,其中 len 是文件长度,buf 起
始的数组存放文件内容;计算“和校验”可用 CHECK_SUM 代替;
4)重复的代码块,在第一次出现时可用方框把代码框住并在右边标记①、
②等序号,下次出现时直接画方框并在内部加上标记即可;
5)可能用到的结构:
:
师
教
课
任
:
号
学
:
名
姓
:
级
班
线
订
装
第1页 共 页
ip头部结构:struct iphdr {#if defined(__LITTLE_ENDIAN_BITFIELD) __u8 ihl:4, version:4; #elif defined (__BIG_ENDIAN_BITFIELD) __u8 version:4, ihl:4;#endif __u8 tos;/*服务类型*/ __u16 tot_len;/*数据包总长*/ __u16 id;/*标识*/ __u16 frag_off;/*标识位和碎片偏移*/ __u8 ttl;/* time to live*/ __u8 protocol;/*协议:TCP、UDP、ICMP等*/ __u16 check;/*首部校验和*/ __u32 saddr;/*源IP地址*/ __u32 daddr;/*目的IP地址*/};icmp头部结构: struct icmphdr { __u8 type; __u8 code; __u16 checksum; union { struct { __u16 id; __u16 sequence; } echo; __u32 gateway; struct { __u16 __unused; __u16 mtu; } frag; } un;};
一、在一个大楼顶端装有一台摄像机,网上的用户可以控制该摄像机,
来观赏周边风景,每个用户每次控制的时间不能超过 2 分钟,且不允
许多人同时控制该摄像机。请设计和实现控制该摄像机的服务器程序,
控制过程可用 CONTROL_CAMERA 表示。(20 分)
1) 问题分析和方案设计
每次只能一个人控制摄像机,因此不需要创建多个子进程;每次控制时间
不 能 超 过 2 分 钟 , 需 要 进 行 超 时 控 制 , 超 时 发 生 时 需 要 结 束 当 前 的
CONTROL_CAMERA。所以设计如下:选择 TCP 协议工作,父进程监听,当有客户
机连接成功,则创建一个子进程,父进程等待子进程结束,再去监听;子进程
设置 2 分钟超时,然后执行 CONTROL_CAMERA,发生超时则子进程退出。
2) 编程
void sigalarm_handler(int sig)
{
exit(0);
}
main()
{
int sock,connfd;
struct sockaddr_in addr;
struct sigaction sigact;
sigact.sa_handler=sigalarm_handler;
sigact.sa_mask=0;
sigact.sa_flags=0;
sigaction(SIGALRM,&sigact,NULL);
if ((sock = socket(AF_INET,SOCK_STREAM,0)) < 0 )
exit(1);
SET_ADDR_PORT;
if ( bind() < 0 )
exit(1);
if ((listen(sock,5) < 0 )
exit(1);
for (;;)
{
connfd = accept();
if(connfd<0)
第2页 共 页
exit(1);
if ( fork() == 0 )
{
}
close(sock);
alarm(120);
CONTROL_CAMERA;
exit(0);
close(connfd);
wait(null);
}
close(sock);
}
二、选择适当的 I/O 模型或服务器模型,在局域网内设计一个聊天程
序。任何一个用户都可以从本方终端上读入字串,发送给对方,并在
对方的终端上显示出来。
(提示: 一方可以多次给对方发数据,而不需要对方响应)(15 分)
1) 问题分析和方案设计
本题需要套接字接收和发送能够同时工作,而不会发生收、发过程互相阻
塞。所以设计如下:选择 TCP 协议工作,创建一个子进程。父进程监听,当有
客户机连接成功,从连接套接字接收数据并显示;子进程则从控制台上读入字
串,然后用主动套接字去与对方连接,发送数据给对方。
2) 编程
void sigchild_handler(int sig)
{
wait(NULL);
}
main()
{
int sock,connfd,sock2;
struct sockaddr_in addr;
string str;
struct sigaction sigact;
sigact.sa_handler=sigchild_handler;
sigact.sa_mask=0;
第3页 共 页
sigact.sa_flags=0;
sigaction(SIGCHLD,&sigact,NULL);
if ( fork() == 0 )
for(;;)
{
cin>>str;
if ((sock2 = socket(AF_INET,SOCK_STREAM,0)) < 0 )
exit(1);
SET_ADDR_PORT;
if(connect()<0)
exit(1);
cin>>str;
write(sock2,str.c_str(),sizeof(str));
close(sock2);
}
exit(0);
{
}
if ((sock = socket(AF_INET,SOCK_STREAM,0)) < 0 )
exit(1);
SET_ADDR_PORT;
if ( bind() < 0 )
exit(1);
if ((listen(sock,5) < 0 )
exit(1);
for (;;)
{
connfd = accept();
if(connfd<0)
exit(1);
char ch[1024];
int n=read(connfd,ch,1024);
close(connfd);
string str(ch);
cout<
三、在一个公园中有 10 万只景观灯,这
些灯只有亮、灭两种状态,并处于同一个
局域网内。请设计和实现一个程序,可以控制这些灯实现任意的亮、
灭状态组合。(20 分)
1) 问题分析和方案设计
本题如采用 tcp 协议,则每轮控制需要 10 万次数据交互,难以满足实时性。
所以设计如下:选择 UDP 协议工作,将指令广播给所有灯;每个灯设置唯一编
号从 0~99999,用 UDP 有效数据的每一位代表一盏灯的亮、灭状态,每个灯依据
编号取出状态位,根据状态位打开或关闭。运行策略存放于磁盘文件上。
2) 编程
main()
{
int sock;
struct sockaddr_in addr;
string str;
if ((sock = socket(AF_INET,SOCK_DGRAM,0)) < 0 )
exit(1);
SET_ADDR_PORT_255;
for (;;)
{
}
int len=READ_FILE(char* buf);
int n=send(sock,buf,len);
sleep(1);
close(sock);
}
四、在 Internet 网上有 100 个主机,这些主机均可响应常用的网络调
试指令,并且其 IP 地址已知。请使用套接字实现一个程序,每隔 30
分钟测试一遍这些域名对应的主机是否能够连通。(15 分)
1) 问题分析和方案设计
本题要测试各主机的连通性,从网络层进行测试即可,而不必关心传输层
使用哪种协议。所以设计如下:选择原始套接字工作,将 ICMP 请求回显指令发
给各个主机,等待主机回复,并计算各个主机的响应时间。
2) 编程
第5页 共 页
void send_icmp(int sockfd,sockaddr_in send_addr);
void recv_icmp(int sockfd,sockaddr_in send_addr);
int main()
{
sockaddr_in addr[100];
SET_ADDR_PORT;
int sockfd;
sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
if(sockfd<0)
return 1;
SET_ADDR_PORT;
for(int i=0;i<100;i++)
{
}
return 0;
send_icmp(sockfd,send_addr[i]);
recv_icmp(sockfd,send_addr[i]);
sleep(3);
}
void send_icmp(int sockfd,sockaddr_in send_addr)
{
}
static short int seq=0;
char buf[8+8];
struct icmphdr *icmp=(struct icmphdr *)buf;
icmp->type=ICMP_ECHO;
icmp->code=0;
icmp->checksum= CHECK_SUM;
icmp->un.echo.id=getpid();
icmp->un.echo.sequence=seq++;
int len=send(sockfd,buf,buflen);
void recv_icmp(int sockfd,sockaddr_in send_addr)
{
char buf[256];
struct icmphdr *icmp;
第6页 共 页
cout<<"recv error"<
ip_hl<<2;
icmplen=n-ipheadlen;
icmp=(struct icmphdr *)(buf+ipheadlen);
if(icmp->type==ICMP_ECHOREPLY)
cout<<"recv from "<
if(pid<0)
exit(1);
else if(pid==0){ //child B,use pipe1&2
cout<<"child B..."<
0)
cout<<"child B received:"<0)
cout<<"child A received:"<