网络编程——基于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流读取和写入文件的方法,添加联系人,删除联系人和显示整个通讯录的方法
三.功能实现截图
图一:客户端功能菜单页面
图二:客户端显示联系人功能实现
图三:客户端添加联系人功能实现
图四:客户端退出通讯录功能实现
图五:服务端功能菜单页面
图六:服务端显示联系人功能实现
图七:服务端添加联系人功能实现
图八:服务端删除联系人功能实现
图九:服务端退出通讯录功能实现
图十:文本文件存储数据
四.代码详细实现
服务端:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
* @ClassName: Server
* @Auther: Drawin
* @Date: 2022/6/8 23:35
* @Description:
*TCP部分:
* 创建serversocket并指定端口号,等待客户端连接
* 客户端访问后读取功能序号
* 读取1,向客户端输出自己的显示功能读取的信息
* 读取2,从客户端读取联系人信息,写入到文件中
*
* 通讯录部分:
* 用IO流和文件储存数据
* 先在服务端实现对文件数据的显示 添加 删除功能
*
*/
public class Server {
public static void main(String[] args) throws Exception {
Function fun=new Function();
//创建服务端socket
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket=serverSocket.accept();//阻塞式监听客户端连接
InputStream is=socket.getInputStream();
BufferedReader br=new BufferedReader(new InputStreamReader(is));//将字节流包装成字符流
PrintStream ps=new PrintStream(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 = new File("student.txt");
fileReader = new FileReader(tf);
buffer = new BufferedReader(fileReader);
line = buffer.readLine();
while (line != null) {
ps.println(line);
line = buffer.readLine();
}
}catch (Exception e){
e.toString();
}
} else if (m == 2) {
Student stu = new Student();
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 = new Scanner(System.in);
int select = scanner.nextInt();
n=select;
switch (select) {
case 1:
fun.Display();
break;
case 2:fun.addInfo();
break;
case 3:{
System.out.println("请输入要删除的联系人的姓名:");
Scanner sin=new Scanner(System.in);
String name=sin.next();
fun.delete(name);
fun.writefile();
}
break;
default:
break;
}
}
}while (n!=4);
//关闭服务
socket.close();
serverSocket.close();
}
}
客户端:
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
/**
* @ClassName: ClientVisit
* @Auther: Drawin
* @Date: 2022/6/8 23:34
* @Description:
*
*
*/
public class ClientVisit {
public static void main(String[] args) throws Exception{
Function act=new Function();
//创建socket客户端口
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),8888);
InputStream is=socket.getInputStream();
BufferedReader br=new BufferedReader(new InputStreamReader(is));//将字节流包装成字符流
PrintStream ps=new PrintStream(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 = new Scanner(System.in);
int select = scanner.nextInt();
n=select;
if (n==1){
ps.println(n);
while (br.readLine()!=null){
System.out.println(br.readLine());}
}
else if(n==2) {
ps.println(n);
Scanner input = new Scanner(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());
}
else if (n==3){
ps.println(n);
break;
}
}while (true);
//关闭服务
socket.close();
}
}
Function类:
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;
/**
* @ClassName: Function
* @Auther: Drawin
* @Date: 2022/6/15 14:43
* @Description: 在此实现显示 增加 删除 的方法
*/
public class Function {
//数据量不多,用数组列表ArrayList
private static ArrayList<Student> arry=new ArrayList<Student>();
public Function() //读文件,将文件中的信息存放在数组列表
{
this.readfile();
}
//根据姓名查找信息,找到返回学号,找不到返回-1
public int find(String str)
{
for (int i = 0; i<arry.size(); i++)
if (arry.get(i).getName().equals(str))
return i;//等于在数组列表的位置
return -1;
}
// 读文件,
public boolean readfile() {
String t=null;
try{
FileReader f1 = new FileReader("student.txt");
BufferedReader br=new BufferedReader(f1);
arry.clear(); // 清除原数组列表中的数据
while ((t= br.readLine())!= null)
{
String [] s=t.split("\\s+");
Student st=new Student(s[0],s[1],s[2],s[3],s[4],s[5]);//注意若该文件每行没有6个字符串,则会出错
arry.add(st);
}
f1.close();
br.close();
return true;
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
return false;
}
}
//添加联系人信息
public boolean add(Student stu)
{
System.out.println();
if (find(stu.getName())!=-1)
return false;//若存在返回false
arry.add(stu);//若不存在则添加信息
return true;
}
public void addInfo() {
//控制台输入
Scanner input = new Scanner(System.in);
Function act = new Function();
//声明一个Student类对象,记录当前学生的信息
Student stu = new Student();
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个元素,否则读取文件并判断是否存在时会出错时会出错,没有输入的用---代替
public boolean writefile() {
FileWriter fw=null;
BufferedWriter out=null;
try {
fw = new FileWriter("student.txt");
out = new BufferedWriter(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();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
//删除联系人信息,并且文件中的内容也要修改
public boolean delete(String s)
{
int pos=find(s);
if (pos==-1)
return false;
arry.remove(pos);
return true;
}
public void Display(){//读取并输出显示文件里的所有信息
FileReader fileReader = null;
BufferedReader br = null;
String line = null;
try {
// Target file path
File testFile = new File("student.txt");
if(!testFile.exists()) {
System.out.println(testFile.getName() + " isn't existed");
}
// Read target file
fileReader = new FileReader(testFile);
br = new BufferedReader(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:数据库类
*/
public class Student {
private String name; /* 姓名 */
private String sex; /* 性别 */
private String age; /* 年龄 */
private String Unit; /* 单位 */
private String phonenumber; /* 手机 */
private String addip; /* 添加IP */
public Student(String name, String sex, String age, String Unit, String phonenumber, String addip) {
this.name=name;
this.sex=sex;
this.age=age;
this.Unit=Unit;
this.phonenumber=phonenumber;
this.addip=addip;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
public String getSex() {
return this.sex;
}
public void setSex(String sex) {
this.sex=sex;
}
public String getAge() {
return this.age;
}
public void setAge(String age) {
this.age=age;
}
public String getUnit() {
return this.Unit;
}
public void setUnit(String callnumber) {
this.Unit=callnumber;
}
public String getphonenumber() {
return this.phonenumber;
}
public void setphonenumber(String home_place) {
this.phonenumber=home_place;
}
public String getaddip() {
return this.addip;
}
public void setaddip(String identityID) {
this.addip=identityID;
}
//从文件中录入的数据格式 "姓名 年龄 性别 单位 手机 添加IP"
public String fileString()
{
return name+" "+age+" "+sex+" "+Unit+" "+phonenumber+" "+addip;
}
}
五.总结
**这是基于Socket编程的计算机网络课程设计,因为当时时间太紧所以我采用的是文字菜单页面,如果有耐心的话可以自己设计一个图形页面试试,会好看很多。文章来源:https://www.toymoban.com/news/detail-462564.html
另外这个程序其实还有一个bug,出现在客户端访问服务端后请求输出文件中的所有内容。服务端直接读取文件并输出在控制台显示没有任何问题,但是通过字符流向客户端输出后,客户端接收再向控制台输出就会丢失偶数行的文件数据。无论如何调试总是想不通问题到底出现在哪里,最后没有办法询问了老师。在老师的建议下,在循环的内外都通过输出一个字符来判断,可是依旧没有看出来丢失数据的原因。最后老师建议直接由服务端向客户端发送一整个文件流,然后在客户端再将文件内容拆分显示输出到控制台。同样由于时间问题我没有再继续尝试,如果有大佬知道为何的话,欢迎讨论并联系告诉我。**文章来源地址https://www.toymoban.com/news/detail-462564.html
到了这里,关于网络编程——基于TCP协议的通讯录【课程设计】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!