还剩19页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
J__a网络编程报告姓名蒋怡学号1107300134题目模拟火车售票退票系统
一、作业要求模拟火车售票退票系统实现一个服务器为多个____,要求
1、服务器用线程池,线程容量为4,座位数为60个,即01-60号座.
2、客户通过网络发送请求可以退票可以买票,先来先服务,买票还是退票由随机数决定,退票必须是该用户买过的有效票,先买的票先退若退票时该用户已没有买到的票,则改为买票若服务器票已售完,则需等待,先来先服务,哪个客户先来,服务器将先为哪个____
3、服务器每次接收一个客户请求需打印该客户的端口号、IP和该用户是买票还是退票,处理该请求之前目前剩余的票所有座号,处理之后剩余的座号也要打印出来,并延迟一个随机处理时间,以模拟对每个客户处理的时间不同将处理结果发给客户
4、客户收到结果后打印到屏幕
5、注意资源共享的问题,适当时可用同步代码,不允许用同步方法注意线程之间的协作演示时开放4-5个用户,并演示一次退票无效的情况(即要退的票在服务器中还没有卖出去,要求2是正常情况)
2、主要设计思路
1、该程序包括以下几个类1)、EchoClient.j__a2)、EchoServer.j__a3)、Node.j__a定义了线性表的一个节点的结构,并对节点进行初始化4)、LList.j__a接口类,包含以下几个方法booleanisEmpty;//判断线性表是否为空intlength;//返回线性表长度Tgetinti;//返回第ii0个元素voidinsertintiTx;//插入x作为第i个元素voidinsert1Tx;//按顺序插入一个数到链表中Tremoveinti;//删除第i个元素并返回被删对象voidappendTx;//在线性表最后插入x元素5)、SingleLinkList.j__a实现接口LList6)、Customer.j__a定义了choise,cus_tickets两个属性和choi__()方法,其中choise是一个随机产生的0或1,用来决定客户买票或退票cus_list是一个线性表,用来存储客户所买到的所有票7)、Tickets.j__a定义了number和list两个属性,其中number用来表示服务器售出的票号,list是一个线性表,用来存储剩余火车票包含了售票票方法sell和退票方法return_ticket
2、思路及流程图1)、首先客户端通过调用Customer类的choi__方法,由choi__方法来决定客户是买票还是退票若choise==1,则客户买票,若choise==0,则客户退票流程图如下2)、若客户买票,则通过输出流将买票信息发送给服务器端若客户退票,则通过“customer.cus_list.isEmpty”这个语句判断客户是否有票可退,若客户有票可退,则通过输出流将退票信息及所退票号发送给服务器端;若客户无票可退,则改为买票,通过输出流将信息发送给服务器端流程图如下3)、服务器端通过输入流接收客户端的信息,接收信息后,随机产生一个时间,线程休眠,模拟网络延迟然后判断客户是买票还是退票,若是买票,则调用Tickets类中的sell方法进行售票处理;若是退票,则调用Tickets类中的return_ticket方法进行退票处理流程图如下4)、若客户是买票的,则通过“list.isEmpty”判断是否有票可售,若有票可售,则进行售票处理(即将list线性表中的第一个节点删除,表示此票已售出),处理后将信息反馈给客户;客户收到服务器端的信息后,将反馈信息打印输出,同时将所买到的票添加到cus_list线性表的最后若无票可售,则线程等待,将线程加入等待队列,当线程被唤醒后,进行售票处理,处理后将信息反馈给客户客户收到服务器端的信息后,输出反馈的信息,同时,将所买到的票添加到cus_list线性表的最后5)、若客户是退票的,首先判断客户所退的票是否是已售出的票,若不是,则非法退票,退票失败,将反馈信息发送给客户端;若是,则进行退票处理(将所要退的票按大小添加到线性表list中),退票处理后,将反馈信息发送给客户端,然后该线程将已经退了的票从cus_list中删除(即cus_list.remove)判断是否有线程在等待队列中,若有,则将队列中的第一个线程唤醒,进行售票处理,然后将反馈信息发送给客户端
3、关键代码1)、EchoClient.j__a2)、EchoServer.j__a3)、Tickets.j__a
4、程序运行截图1)、服务器端截图当票已售完时,客户请求买票就将客户加入一个等待队列,如果有另一个客户来退票,则将所退的票售给等待队列中的第一个客户当所非法退票情况演示控制客户退票号为20的票,因为20号票还未售出,所以退票失败!2)、客户端截图客户请求退票时,客户无票可退,转为买票情况
5、实验总结通过本次实验,掌握了ServerSocket的用法和多线程编程的的原理、还有同步代码块的使用、线程等待和唤醒的使用,在实验过程中遇到了很多不明白的问题,通过找书、与同学讨论都一一解决了第一次实验的时候,基本上不知道从何处入手,但是通过慢慢的摸索和研究,一步一步地将一个个小问题解决,才能将程序编写出来在调试过程中,遇到了很多奇奇怪怪的问题,很多时候是因为自己的考虑不够全面和逻辑出来的错误所引起的,在同学的帮助下,把这些问题都一一解决了客户买票choi__=int__th.random*2choise==1客户退票票是否否是客户退票客户拥有的票是否为空发送退票信息给服务器端发送买票信息给服务器端客户买票发送买票信息给服务器端接收客户端的信息线程休眠一段时间客户是否买票tickets.sellTickets.return_ticket否是客户收到服务器端反馈信息打印输出信息cus_list.append否是否有票可售售票处理是售票线程等待线程被唤醒后进行售票处理将线程加入等待队列将反馈信息发送到客户端退票是否成功打印输出退票成功信息cus_list.remove是输出退票失败信息客户端收到服务器端的反馈信息否等待队列是否空退票该票是否已售出否非法退票,退票失败是退票处理将所退的票售给第一个等待的线程将反馈信息发送到客户端fori=1;i=500;i++{System.out.println客户第+i+次请求;//msg=customer.choi__;//choi__产生随机数来确定客户是买票还是退票ifmsg.equalsbuy{pw.printlnmsg;//将客户买票的信息传给服务器System.out.printlnbr.readLine;//输出服务器传给客户的买到票的信息customer.cus_list.appendbr.readLine;//将客户买到的票放入链表的最后System.out.printlncustomer.cus_list+\n;//输出客户所拥有的所有票,cus_list用一个链表存储客户所拥有的所有票}elseifmsg.equalsrefund{if!customer.cus_list.isEmpty//若客户所拥有的票不是空的,就退票{pw.printlnmsg;//将客户退票的信息传给服务器pw.printlncus_number=customer.cus_list.get1;//获取客户最先买到的那张票,将其传给服务器msg=br.readLine;//接收服务器的反馈信息if!msg.equals非法退票!退票失败!{System.out.printlnmsg;customer.cus_list.remove1;//将客户所退了的票从客户所拥有的票中移除System.out.printlncustomer.cus_list+\n;//输出客户所拥有的所有票}elseSystem.out.printlnmsg;}else//否则,转为买票{System.out.println客户没有票可退转为买票;pw.printlnbuy;//将买票信息传给服务器System.out.printlnbr.readLine;//输出服务器传给客户的买到票的信息customer.cus_list.appendbr.readLine;//将客户买到的票放入链表的最后System.out.printlncustomer.cus_list+\n;//输出客户所拥有的所有票,cus_list用一个链表存储客户所拥有的所有票}}}publicclassEchoServer{privateintport=8001;privateServerSocketserverSocket;privateExecutorServi__executorServi__;//线程池privatefinalintPOOL_SIZE=4;//单个CPU时线程池中工作线程的数目ListSocketsocketList=newArrayListSocket;//排队序列publicEchoServerthrowsIOEx__ption{serverSocket=newServerSocketport;serverSocket.setRe__iveBufferSize50;//创建线程池executorServi__=Executors.newFixedThreadPoolPOOL_SIZE;System.out.println服务器启动;}publicvoidservi__{whiletrue{Socketsocket=null;try{socket=serverSocket.ac__pt;executorServi__.executenewHandlersocketsocketList;}catchIOEx__ptione{e.printStackTra__;}}}publicstaticvoid__inStringargs[]throwsIOEx__ption{newEchoServer.servi__;}}classHandlerimplementsRunnable{privateSocketsocket;privateTicketsticket=newTickets;ListSocketsocketList=newArrayListSocket;//排队序列publicHandlerSocketsocketListSocketsocketList{this.socket=socket;this.socketList=socketList;}privatePrintWritergetWriterSocketsocketthrowsIOEx__ption{OutputStreamsocketOut=socket.getOutputStream;returnnewPrintWritersocketOuttrue;}privateBufferedReadergetReaderSocketsocketthrowsIOEx__ption{InputStreamsocketIn=socket.getInputStream;returnnewBufferedReadernewInputStreamReadersocketIn;}publicStringechoStringmsg{returnecho:+msg;}@SuppressWarningsstatic-ac__sspublicvoidrun{try{System.out.printlnNewconnectionac__pted+socket.getInetAddress+:+socket.getPort;BufferedReaderbr=getReadersocket;PrintWriterpw=getWritersocket;Stringmsg=null;Stringcus_number=null;whilemsg=br.readLine!=null{//模拟售票的网络延迟try{Thread.sleeplong__th.random*3000;//产生一个随机处理时间}catchInterruptedEx__ptione{e.printStackTra__;}ifmsg.equalsbuy{ticket.sellsocketListsocketpw;}elseifmsg.equalsrefund{ticket.return_ticketcus_number=br.readLinesocketsocketListpw;}}}catchIOEx__ptione{e.printStackTra__;}finally{try{ifsocket!=nullsocket.close;}catchIOEx__ptione{e.printStackTra__;}}}}publicclassTickets{Stringnumber;//售出票的序号staticStringtickets[]={123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960};staticSingleLinkListStringlist=newSingleLinkListStringtickets;//用list链表存储火车票publicvoidsellListSocketsocketListSocketsocketPrintWriterpw{synchronizedlist{System.out.printlnsocket.getPort+客户买票;System.out.print客户买票前剩余火车票为;System.out.printlnthis.list;//打印还剩多少张票可卖iflist.isEmpty//若无票可售,则将线程加入等待队列{System.out.println暂时无票!排队中......;socketList.addsocket;System.out.println客户:+socket.getInetAddress+:+socket.getPort+,队列长度:+socketList.toArray.length;System.out.println等待队列的第一个客户为:+socketList.get
0.getPort+\n;try{list.wait;}catchInterruptedEx__ptione{//TODOAuto-generatedcatchblocke.printStackTra__;}number=list.remove1;System.out.println票号:+number+被队首:+socketList.get
0.getPort+预定成功\n;socketList.remove0;pw.println客户买到的票的票号为+number;//将客户买到票的信息传回给客户pw.printlnnumber;//将客户买到的票号传给客户}else{//若符合条件进行售票number=list.remove1;//每次票号最小的票售出,将已售出的票从火车票链表中移除System.out.println售出票的序号为 +number;//打印售出票的信息System.out.print客户买票后剩余火车票为;System.out.printlnlist+\n;//打印售票后所剩余的火车票pw.println客户买到的票的票号为+number;//将客户买到票的信息传回给客户pw.printlnnumber;//将客户买到的票号传给客户}}}publicvoidreturn_ticketStringcus_numberSocketsocketListSocketsocketListPrintWriterpw{//将客户所退的票按顺序添加的票号里面synchronizedlist{inti;fori=1;i=list.length;i++{iflist.geti.equalscus_number//判断客户所退的票是否是服务器以售出的票,若不是,则非法退票{pw.println非法退票!退票失败!;System.out.println非法退票!退票失败!\n;return;}}list.insert1cus_number;//将客户退的票按顺序插入到火车票链表中System.out.printlnsocket.getPort+客户退票所退票号为:+cus_number;System.out.print客户退票后剩余火车票为;System.out.printlnlist+\n;pw.println客户退票所退票号为:+cus_number;//将客户退票信息传回给客户if!socketList.isEmpty//退票后判断队列中是否有客户在等待买票,若是,则将所退的票买给队列中的第一个客户{list.notify;//唤醒线程}}}}。