前阵子嵌入式系统实验课,正好在自学java,就用java实现了一个简单的聊天室
由于学校机房的嵌入式系统没有安装图形化界面的相关环境,自行安装比较麻烦,就写了一个没有图形化界面的聊天室系统
简单的分为客户端和服务端,通过socket建立连接,IO流传输数据,下面是代码
Client:
import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.util.Scanner;
public class Client {
private Socket socket;
private DataInputStream dataInputStream=null;
private DataOutputStream dataOutputStream=null;
private static DataOutputStream filewrite=null;
private static DataInputStream fileread=null;
private static File transferFile=null;
public static void main(String[] args) {
Client client = new Client();
client.start();
}
public Client() {
//用于与服务器建立连接
try {
String host="localhost"; //默认为本地ip
System.out.print("\t 请输入ip:");
Scanner sc= new Scanner(System.in); //创建一个Scanner接收ip地址
host=sc.next();
System.out.println("正在连接服务端...");
socket = new Socket(host,6666); //创建socket套接字,
// 连接到对应ip的6666号端口
System.out.println("与服务端建立连接!");
dataOutputStream=new DataOutputStream(socket.getOutputStream());
dataInputStream=new DataInputStream(socket.getInputStream());
//创建输出流,用于发送和接收消息
System.out.println("\t 可以输入“name:+昵称“的方式设置昵称,否则昵称默认为本地ip");
System.out.println("\t 可以用“ @ + 对方ip/昵称 @ + 内容 ”的形式私聊对方");
System.out.println("\t 可以用“file: +文件目录” 的形式传输文件到服务器");
} catch (Exception e) {
e.printStackTrace();
}
}
public void start() {
try {
//首先读取服务端发送过来的消息的线程启动
ServerHandler handler = new ServerHandler();
Thread t = new Thread(handler);
t.start();
Scanner scanner = new Scanner(System.in);
while(true) { //一直运行,接收键盘输入信息
StringBuilder Message = new StringBuilder(scanner.nextLine());
if(Message.length()>5&&Message.substring(0,5).equals("file:")){
//用于判断是否为文件信息
dataOutputStream.writeUTF(Message.toString());
String filepath=Message.substring(5, Message.length());//获取文件路径
transferFile=new File(filepath); //创建文件
fileread=new DataInputStream(new FileInputStream(transferFile));//创建文件输出流
dataOutputStream.writeUTF(transferFile.getName());//输出文件名称
System.out.println("发送的文件名为:"+transferFile.getName());
long length=transferFile.length();//获取文件名称
dataOutputStream.writeLong(length);//输出文件长度
System.out.println("发送的文件名长度为"+length+"字节");
//使用文件读取流和文件传输流
long size=length/2048;
if(size<1){
byte[] data=new byte[(int) length];
fileread.read(data);
dataOutputStream.write(data);
System.out.println("文件上传完毕");
}
else{
byte[] data=new byte[(int) length];
while(size>0){
fileread.read(data);
dataOutputStream.write(data);
size--;
}
byte[] end=new byte[(int) (length-2048*size)];
fileread.read(end);
dataOutputStream.write(end);
System.out.println("文件上传完毕");
}
System.out.println("文件"+transferFile+"上传成功!");
}
else{
dataOutputStream.writeUTF(Message.toString());//如果不是输出文件则为文字信息
dataOutputStream.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private class ServerHandler implements Runnable{
@Override
public void run() {
try {
while(true){
//继承Runnable接口,重新定义run方法,用数据接受流接收服务端传来的信息
System.out.println(dataInputStream.readUTF());
}
} catch (SocketException e) {
System.out.println("退出聊天室");
}catch (IOException e){
e.printStackTrace();
}
}
}
}
Server:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
public class Server {
private ServerSocket server;
private List<ClientHandler> clientHandlerList=new ArrayList<>();//创建
private static String filepath="/root/Pictures/";//设置服务的文件存储位置
//private static String filepath="C:\\Users\\joy\\Desktop\\local";
public static void main(String[] args) {
Server server = new Server(); //主程序,用于调用主函数
server.start();
}
public Server() {
try {
System.out.println("正在启动服务端...");
server = new ServerSocket(6666);//创建服务端Socket
System.out.println("启动服务端完毕!");
System.out.println("等待客户端连接...");
} catch (IOException e) {
e.printStackTrace();
}
}
public void start() {
try {
while(true) {
Socket socket = server.accept();//接收客户端连接的socket
System.out.println("客户端"+socket.getInetAddress().getHostAddress()+"连接了!");
//启动一个线程处理该客户端交互
ClientHandler handler = new ClientHandler(socket);//创建一个ClientHandler处理连接的客户端连接的socket
clientHandlerList.add(handler);//将新添加的ClientHandler加入ClientHandkerList中
new Thread(handler).start();//启动该线程
}
} catch (IOException e) {
e.printStackTrace();
}
}
private class ClientHandler implements Runnable{//定义ClientHandler线程
private Socket socket;//存储客户端的socket,每个客户端对应一个
private String host;//存储一个host
private String name="";//初始化name
private DataInputStream dataInputStream=null;//文字传输流
private DataOutputStream dataOutputStream=null;
private DataInputStream filereader=null;//文件传输流
private DataOutputStream filewriter=null;
public ClientHandler(Socket socket) {
this.socket = socket;
host = socket.getInetAddress().getHostAddress();//获取客户端对应的socket
}
public void run() {
try {
dataInputStream=new DataInputStream(socket.getInputStream());//获取文字传输流
dataOutputStream=new DataOutputStream(socket.getOutputStream());
while(true){
String Message=dataInputStream.readUTF();//接收客户端发来的信息,并对信息进行判断
if(Message.length()>=5&&Message.substring(0,5).equals("file:")){//文件的判断
String fileName=dataInputStream.readUTF();//获取文件名
System.out.println("接受到的文件名为"+fileName);
//创建文件
File file=new File(filepath+System.getProperties().get("file.separator")+fileName);
long length=dataInputStream.readLong();//获取客户端传来的文件长度
System.out.println("接收到的文件长度为"+length+"字节");
//创建文件传输流
filewriter =new DataOutputStream(new FileOutputStream(file,true));
//文件传输
long size=length/2048;
if(size<1){
byte[] data=new byte[(int) length];
dataInputStream.read(data);
filewriter.write(data);
System.out.println("文件接收完毕");
}
else{
byte[] data=new byte[2048];
byte[] end =new byte[(int)(length-2048*size)];
while(size>0){
dataInputStream.read(data);
filewriter.write(data);
size--;
}
dataInputStream.read(end);
filewriter.write(data);
System.out.println("文件接收完毕");
}
}
//判断是否为私聊信息
else if(Message.length()>1&&Message.substring(0,1).equals("@")){
String sourcehost=Message.substring(1,Message.lastIndexOf("@"));//判断第一个字符是否为@
String Message01=Message.substring(Message.lastIndexOf("@")+1,Message.length());//获取私聊内容
StringBuilder Message02= new StringBuilder("");
if(!(name.equals(""))){
Message02= new StringBuilder(name + " 私聊对你说:" + Message01);//包装发送的信息
System.out.println(name+"对"+sourcehost+"私聊说"+Message01);
}
else{
Message02= new StringBuilder(host + " 私聊对你说:" + Message01);
System.out.println(host+"对"+sourcehost+"私聊说"+Message01);
}
for (int i = 0; i < clientHandlerList.size(); i++) {//遍历clientHandlder
if(clientHandlerList.get(i).getHost().equals(sourcehost)||clientHandlerList.get(i).getName().equals(sourcehost)){
//判断clientHandlerList中的host或者name是否为私聊对象
clientHandlerList.get(i).getDataOutputStream().writeUTF(Message02.toString());
break;
}
}
}
else if(Message.length()>=5&&Message.substring(0,5).equals("name:")){//判断是否为设置名字
setName(Message.substring(5,Message.length()));
}
else {
//普通文字输出
StringBuilder realMessage= new StringBuilder("");
if(!(name.equals(""))){//对数据进行煲装
realMessage= new StringBuilder(name + " 说:" + Message);
}
else{
realMessage= new StringBuilder(host + " 说:" + Message);
}
System.out.println(realMessage);
for (int i = 0; i < clientHandlerList.size(); i++) {
clientHandlerList.get(i).getDataOutputStream().writeUTF(realMessage.toString());
}
}
}
} catch (IOException e) {//捕捉IO传输中的异常
try{
socket.close();//如果出现异常,关闭socket
clientHandlerList.remove(this);//并从clientHandlerList中移除该clientHanlderList
}catch (IOException e1){
e1.printStackTrace();
}
}
finally {
try{
System.out.println(host+"退出聊天室");//正常退出时的输出
dataInputStream.close();
dataOutputStream.close();
socket.close();
clientHandlerList.remove(this);
}catch (IOException e){
e.printStackTrace();
}
}
}
public Socket getSocket() {
return socket;
}
public String getHost() {
return host;
}
public DataInputStream getDataInputStream() {
return dataInputStream;
}
public DataOutputStream getDataOutputStream() {
return dataOutputStream;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
实验结束后,还留下几个bug没有解决,主要是发送文件后会自动退出聊天室,但是由于时间原因就没去深究。