网络编程——基于TCP协议的通讯录【课程设计】
本文目录
一.设计题目和要求
题目:基于TCP协议的通讯录
设计目标:
(1)了解Socket通信的原理,在此基础上编写一个基于TCP协议的通讯录;
(2)理解TCP通信原理;
课程设计系统组成及模块功能:
此TCP/IP课程设计实现了基于TCP的客户/服务器通信程序,需要实现以下一些基本功能:
(1)客户端连接服务器;
(2)客户端读取键盘输入发送给服务器请求服务
(3)服务端响应后执行功能并发送给客户端显示输出
(4)服务端也可以自行执行功能
(5)文本文件做数据载体
要求:
(1)编写程序,实现系统的基本功能,鼓励自行增加新功能;
(2)要有用户界面:要求至少采用文本菜单界面;鼓励采用图形菜单界面;
效果图:客户端
服务端:数据存储:
运行界面:
二.设计内容
服务端
- 创建ServerSocket并指定端口号,用accept方法等待客户端连接
- 用BufferedReader类和PrintStream类包装socket的输入输出流,首先从客户端读入字符并转换为整型,判断请求的服务是获取通讯录信息还是添加信息到通讯录。
- 若是获取通讯录信息则从文本文件中读取所有内容并输出给客户端
- 若是添加信息到通讯录则从客户端继续读取添加联系人的相关信息并写入到文本文件中
- 服务端也能独立访问通讯录内容并且能实现对通讯录的显示,添加联系人和删除联系人的功能,从键盘读入执行功能序号并用switch和do while循环结合判断,当从键盘读入退出功能时,关闭socket和serversocket服务
客户端
- 创建socket客户端口并指定本机IP地址和服务器端口号,同样用BufferedReader类和PrintStream类将字节流输入输出包装成字符流
- 连接服务器成功后显示文字菜单页面,从键盘读入功能序号,并输出给服务器端
- 若是请求访问整个通讯录内容,则从服务器端读入文件
- 若是请求添加联系人到通讯录,则继续从键盘读入联系人数据并输出给服务器端
- 用do while循环重复执行文字菜单页面直到从键盘读入退出功能时关闭socket
Student类
封装了通讯录的联系人信息形式,包括姓名,性别,年龄,单位,手机,添加IP六个私有属性,以及所有属性的构造方法,可以通过get和set方法获取和写入所有属性的值,同时提供输出整行联系人信息的方法
Function类
封装了通过IO流读取和写入文件的方法,添加联系人,删除联系人和显示整个通讯录的方法
三.功能实现截图
图一:客户端功能菜单页面

图二:客户端显示联系人功能实现

图三:客户端添加联系人功能实现

图四:客户端退出通讯录功能实现

图五:服务端功能菜单页面

图六:服务端显示联系人功能实现

图七:服务端添加联系人功能实现

图八:服务端删除联系人功能实现

图九:服务端退出通讯录功能实现

图十:文本文件存储数据
四.代码详细实现
服务端:
importjava.io.*;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.Scanner;/**
* @ClassName: Server
* @Auther: Drawin
* @Date: 2022/6/8 23:35
* @Description:
*TCP部分:
* 创建serversocket并指定端口号,等待客户端连接
* 客户端访问后读取功能序号
* 读取1,向客户端输出自己的显示功能读取的信息
* 读取2,从客户端读取联系人信息,写入到文件中
*
* 通讯录部分:
* 用IO流和文件储存数据
* 先在服务端实现对文件数据的显示 添加 删除功能
*
*/publicclassServer{publicstaticvoidmain(String[] args)throwsException{Function fun=newFunction();//创建服务端socketServerSocket serverSocket =newServerSocket(8888);Socket socket=serverSocket.accept();//阻塞式监听客户端连接InputStream is=socket.getInputStream();BufferedReader br=newBufferedReader(newInputStreamReader(is));//将字节流包装成字符流PrintStream ps=newPrintStream(socket.getOutputStream());//printstream中有写出换行的方法int m;do{int num =Integer.valueOf(br.readLine());//从客户端读入
m=num;if(m ==1){FileReader fileReader =null;BufferedReader buffer =null;String line =null;try{File tf =newFile("student.txt");
fileReader =newFileReader(tf);
buffer =newBufferedReader(fileReader);
line = buffer.readLine();while(line !=null){
ps.println(line);
line = buffer.readLine();}}catch(Exception e){
e.toString();}}elseif(m ==2){Student stu =newStudent();
ps.println("请输入联系人的基本信息=====>");
ps.println("姓名:");String sname = br.readLine();
ps.println("年龄:");String sage = br.readLine();
ps.println("性别:");String ssex = br.readLine();
ps.println("单位:");String sunit = br.readLine();
ps.println("手机:");String spn = br.readLine();
ps.println("添加IP:");String ip = br.readLine();
stu.setName(sname);
stu.setAge(sage);
stu.setSex(ssex);
stu.setUnit(sunit);
stu.setphonenumber(spn);
stu.setaddip(ip);
fun.add(stu);
fun.writefile();}}while(m!=3);int n;do{{System.out.println("**********************************欢迎使用基于TCP的通讯录 服务端****************************");System.out.println("\t\t\t1.显示所有联系人信息");System.out.println("\t\t\t2.添加联系人信息");System.out.println("\t\t\t3.删除联系人信息");System.out.println("\t\t\t4.退出通讯录");System.out.println("*****************************************************************************************");System.out.println("请输入您想要执行的功能序号:");Scanner scanner =newScanner(System.in);int select = scanner.nextInt();
n=select;switch(select){case1:fun.Display();break;case2:fun.addInfo();break;case3:{System.out.println("请输入要删除的联系人的姓名:");Scanner sin=newScanner(System.in);String name=sin.next();
fun.delete(name);
fun.writefile();}break;default:break;}}}while(n!=4);//关闭服务
socket.close();
serverSocket.close();}}
客户端:
importjava.io.*;importjava.net.InetAddress;importjava.net.Socket;importjava.util.Scanner;/**
* @ClassName: ClientVisit
* @Auther: Drawin
* @Date: 2022/6/8 23:34
* @Description:
*
*
*/publicclassClientVisit{publicstaticvoidmain(String[] args)throwsException{Function act=newFunction();//创建socket客户端口Socket socket =newSocket(InetAddress.getByName("127.0.0.1"),8888);InputStream is=socket.getInputStream();BufferedReader br=newBufferedReader(newInputStreamReader(is));//将字节流包装成字符流PrintStream ps=newPrintStream(socket.getOutputStream());//printstream中有写出换行的方法int n;do{System.out.println("**********************************欢迎使用基于TCP的通讯录 客户端****************************");System.out.println("\t\t\t1.显示所有联系人信息");System.out.println("\t\t\t2.添加联系人信息");System.out.println("\t\t\t3.退出通讯录");System.out.println("*****************************************************************************************");System.out.println("请输入您想要执行的功能序号:");Scanner scanner =newScanner(System.in);int select = scanner.nextInt();
n=select;if(n==1){
ps.println(n);while(br.readLine()!=null){System.out.println(br.readLine());}}elseif(n==2){
ps.println(n);Scanner input =newScanner(System.in);System.out.println(br.readLine());System.out.println(br.readLine());
ps.println(input.next());System.out.println(br.readLine());
ps.println(input.next());System.out.println(br.readLine());
ps.println(input.next());System.out.println(br.readLine());
ps.println(input.next());System.out.println(br.readLine());
ps.println(input.next());System.out.println(br.readLine());
ps.println(input.next());}elseif(n==3){
ps.println(n);break;}}while(true);//关闭服务
socket.close();}}
Function类:
importjava.io.*;importjava.util.ArrayList;importjava.util.Scanner;/**
* @ClassName: Function
* @Auther: Drawin
* @Date: 2022/6/15 14:43
* @Description: 在此实现显示 增加 删除 的方法
*/publicclassFunction{//数据量不多,用数组列表ArrayListprivatestaticArrayList<Student> arry=newArrayList<Student>();publicFunction()//读文件,将文件中的信息存放在数组列表{this.readfile();}//根据姓名查找信息,找到返回学号,找不到返回-1publicintfind(String str){for(int i =0; i<arry.size(); i++)if(arry.get(i).getName().equals(str))return i;//等于在数组列表的位置return-1;}// 读文件,publicbooleanreadfile(){String t=null;try{FileReader f1 =newFileReader("student.txt");BufferedReader br=newBufferedReader(f1);
arry.clear();// 清除原数组列表中的数据while((t= br.readLine())!=null){String[] s=t.split("\\s+");Student st=newStudent(s[0],s[1],s[2],s[3],s[4],s[5]);//注意若该文件每行没有6个字符串,则会出错
arry.add(st);}
f1.close();
br.close();returntrue;}catch(IOException e){// TODO 自动生成的 catch 块
e.printStackTrace();returnfalse;}}//添加联系人信息publicbooleanadd(Student stu){System.out.println();if(find(stu.getName())!=-1)returnfalse;//若存在返回false
arry.add(stu);//若不存在则添加信息returntrue;}publicvoidaddInfo(){//控制台输入Scanner input =newScanner(System.in);Function act =newFunction();//声明一个Student类对象,记录当前学生的信息Student stu =newStudent();System.out.println("请输入联系人的基本信息=====>");System.out.print("姓名:");String sname = input.next();System.out.print("年龄:");String sage = input.next();System.out.print("性别:");String ssex = input.next();System.out.print("单位:");String sunit = input.next();System.out.print("手机:");String spn = input.next();System.out.print("添加IP:");String ip = input.next();
stu.setName(sname);
stu.setAge(sage);
stu.setSex(ssex);
stu.setUnit(sunit);
stu.setphonenumber(spn);
stu.setaddip(ip);System.out.println(stu.fileString());
act.add(stu);
act.writefile();}//写文件,注意每行必须有6个元素,否则读取文件并判断是否存在时会出错时会出错,没有输入的用---代替publicbooleanwritefile(){FileWriter fw=null;BufferedWriter out=null;try{
fw =newFileWriter("student.txt");
out =newBufferedWriter(fw);//姓名性别等信息中间隔一个空格for(int i=0;i<arry.size();i++){String s=arry.get(i).fileString();System.out.println(arry.get(i).fileString());
out.write(s);
out.newLine();}
out.close();
fw.close();returntrue;}catch(IOException e){
e.printStackTrace();returnfalse;}}//删除联系人信息,并且文件中的内容也要修改publicbooleandelete(String s){int pos=find(s);if(pos==-1)returnfalse;
arry.remove(pos);returntrue;}publicvoidDisplay(){//读取并输出显示文件里的所有信息FileReader fileReader =null;BufferedReader br =null;String line =null;try{// Target file pathFile testFile =newFile("student.txt");if(!testFile.exists()){System.out.println(testFile.getName()+" isn't existed");}// Read target file
fileReader =newFileReader(testFile);
br =newBufferedReader(fileReader);
line = br.readLine();while(line !=null){System.out.println(line);// Notice: the following statement is necessary.
line = br.readLine();}}catch(Exception e){
e.toString();}finally{if(br !=null){try{
br.close();}catch(Exception e){
e.toString();
br =null;}}if(fileReader !=null){try{
fileReader.close();}catch(Exception e){
e.toString();}}}}}
Student类:
/**
* @ClassName: DataBase
* @Auther: Drawin
* @Date: 2022/6/8 23:39
* @Description:数据库类
*/publicclassStudent{privateString name;/* 姓名 */privateString sex;/* 性别 */privateString age;/* 年龄 */privateStringUnit;/* 单位 */privateString phonenumber;/* 手机 */privateString addip;/* 添加IP */publicStudent(String name,String sex,String age,StringUnit,String phonenumber,String addip){this.name=name;this.sex=sex;this.age=age;this.Unit=Unit;this.phonenumber=phonenumber;this.addip=addip;}publicStudent(){}publicStringgetName(){return name;}publicvoidsetName(String name){this.name=name;}publicStringgetSex(){returnthis.sex;}publicvoidsetSex(String sex){this.sex=sex;}publicStringgetAge(){returnthis.age;}publicvoidsetAge(String age){this.age=age;}publicStringgetUnit(){returnthis.Unit;}publicvoidsetUnit(String callnumber){this.Unit=callnumber;}publicStringgetphonenumber(){returnthis.phonenumber;}publicvoidsetphonenumber(String home_place){this.phonenumber=home_place;}publicStringgetaddip(){returnthis.addip;}publicvoidsetaddip(String identityID){this.addip=identityID;}//从文件中录入的数据格式 "姓名 年龄 性别 单位 手机 添加IP"publicStringfileString(){return name+" "+age+" "+sex+" "+Unit+" "+phonenumber+" "+addip;}}
五.总结
**这是基于Socket编程的计算机网络课程设计,因为当时时间太紧所以我采用的是文字菜单页面,如果有耐心的话可以自己设计一个图形页面试试,会好看很多。
另外这个程序其实还有一个bug,出现在客户端访问服务端后请求输出文件中的所有内容。服务端直接读取文件并输出在控制台显示没有任何问题,但是通过字符流向客户端输出后,客户端接收再向控制台输出就会丢失偶数行的文件数据。无论如何调试总是想不通问题到底出现在哪里,最后没有办法询问了老师。在老师的建议下,在循环的内外都通过输出一个字符来判断,可是依旧没有看出来丢失数据的原因。最后老师建议直接由服务端向客户端发送一整个文件流,然后在客户端再将文件内容拆分显示输出到控制台。同样由于时间问题我没有再继续尝试,如果有大佬知道为何的话,欢迎讨论并联系告诉我。**
版权归原作者 年迈的小笼包 所有, 如有侵权,请联系我们删除。