JAVA聊天器
本次实验室基于课本例15.3、15.4程序改进的JAVA聊天器程序
阶段一:实现两个客户端之间的通信。
问题1:怎样实现两个客户端的连接?
每有一个客户端启动,服务器程序就会监听并且返回一个与客户端连接的socket套接字,所以将这些套接字放在一个数组(arraylist中也行)中,数组下标+1就是该客户端的编号,这样就能够在客户端启动后主动去连接另一个客户端。其实就是在服务器中连接到另一客户端与服务器连接的套接字,然后可以实现连接。
问题2:两个客户端连接后都只能让第二个客户端发出消息后才能够将消息显示出来
这里我用了InputStream in = socket.getInputStream()对象的in.available() 方法来判断输入流中是否有字节的存在来解决问题;
阶段一的效果:
只能够实现每次一条一条发的效果
改进目标: 实现能够自由发送 不再是客户端1一条客户端2一条的效果。
阶段二: 实现能够自由发送消息,发消息与收消息不再有限制
解决办法: 将发消息和收消息分为两个线程,两个线程互不干扰来实现。
问题1: java.lang.NumberFormatException
在做的过程中出现了数字类型转换的异常,原因是使用Integer.parseInt() 将字符串转化为数字时出现了问题。现已解决
运行效果:
下一阶段,实现文件的端到端的传输
阶段三:文件的传输
查找的资料:
-
read()函数,从输入流读取一些字节数,然后存储到缓冲区b 返回读取到字节的数目 (int).
-
String.valueOf(int i) : 将 int 变量 i 转换成字符串
实现的程度: 发送文件与接收文件都没问题,但是接收文件方目前无法指定接收文件的路径
原因如下:
接收部分的代码: 发送部分的代码:
如果是这样的话 在接收代码的第四行filepath = sin.readLine()是要从键盘输入保存文件的路径,但是 发送消息代码的第8行和第14行的readline = sin.readLine() 而发送跟接收是两个互不干扰的线程,输入时就会混乱不知道谁接收到了。 目前不知道怎么解决。
除了无法指定接收文件的路径外没有其他的问题,下面是用来测试可以收发文件
效果如下:
Client1: client2:
Client这里是可以指定文件路径的,但是client2不行,目前不知道怎么解决
服务器代码
package Server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class MultiTalkServer {
static int clientnum = 0;//静态成员变量,记录客户端的个数
public static Socket[] arraysocket = new Socket[100];
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
try{
//创建一个ServerSocket在端口4700监听客户请求
serverSocket = new ServerSocket(4700);
}catch(Exception e){
System.out.println("can not listen on port: 4700. ");
System.exit(-1); // 退出
}
while(listening){ //循环监听
//监听到客户请求,根据得到的Socket对象和客户计数创建并启动服务线程
arraysocket[clientnum] = serverSocket.accept();// 每当有一个客户端启动就与其连接一个服务器的socket
new ServerThread(arraysocket[clientnum],clientnum).start();//启动线程
clientnum++;
}
serverSocket.close(); //关闭serverSocket
}
}
package Server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class MultiTalkServer {
static int clientnum = 0;//静态成员变量,记录客户端的个数
public static Socket[] arraysocket = new Socket[100];
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
try{
//创建一个ServerSocket在端口4700监听客户请求
serverSocket = new ServerSocket(4700);
}catch(Exception e){
System.out.println("can not listen on port: 4700. ");
System.exit(-1); // 退出
}
while(listening){ //循环监听
//监听到客户请求,根据得到的Socket对象和客户计数创建并启动服务线程
arraysocket[clientnum] = serverSocket.accept();// 每当有一个客户端启动就与其连接一个服务器的socket
new ServerThread(arraysocket[clientnum],clientnum).start();//启动线程
clientnum++;
}
serverSocket.close(); //关闭serverSocket
}
}
客户端代码
package Client;
import java.net.Socket;
public class TalkClient {
public static boolean isent = false;
public static void main(String[] args) {
try{
//向本机的4700端口发出客户端请求
Socket socket = new Socket("127.0.0.1",4700);
SentThread sent = new SentThread(socket); //创建发送线程的对象
ReceiveThread receive = new ReceiveThread(socket); //创建接收线程的对象
//启动两个线程
receive.start();
sent.start();
}catch(Exception e){
System.out.println("Error: " + e); //在显示屏上输出错误信息
}
}
}
package Client;
import java.io.*;
import java.net.Socket;
public class SentThread extends Thread{//发送消息的线程
Socket socket = null;//保存本线程相关的Socket对象
public SentThread(Socket s){
socket = s;
}
public void SentFile(Socket socket,String filepath){
try {
OutputStream os = socket.getOutputStream();
FileInputStream is = new FileInputStream(new File(filepath));
byte[] bs = new byte[1024];
int num = 0;
while((num = is.read(bs)) != -1){
os.write(bs,0,num);
os.flush();
}
System.out.println("发送完毕");
}catch(Exception e){
System.out.println("Error" + e);
}
}
public void run(){
try{
//由socket对象得到输出流,并构造相应的PrintWriter对象
PrintWriter os = new PrintWriter(socket.getOutputStream());
String readline = null;
BufferedReader sin = new BufferedReader((new InputStreamReader((System.in))));
System.out.println(" what client do you want to message?");
String num = sin.readLine();//得到另一socket的编号
os.println(num);
readline = sin.readLine();//输入要发送的内容
String signal = "sentfile";
while(!readline.equals("bye")){
File file = new File(readline);
if(file.exists()){
os.println(signal);
os.flush();
SentFile(socket,readline);
readline = sin.readLine();
}
else{
os.println(readline); //将消息发送给Server
os.flush(); //刷新输出流,使Server马上收到字符串
System.out.println("me: " + readline);
readline = sin.readLine(); // 接收下一条消息
}
}
}
catch (Exception e){
System.out.println("Error" + e);
}
}
}
package Client;
import java.io.*;
import java.net.Socket;
public class ReceiveThread extends Thread {
Socket socket = null; //保存本线程相关的Socket
String filepath;
public ReceiveThread(Socket s){
socket = s;
}
public void ReceiveFile(Socket socket,String filepath){
try{
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream(new File(filepath));
byte[] bs = new byte[1024];
int num;
while((num = is.read(bs))!=-1){
fos.write(bs,0,num);
fos.flush();
}
System.out.println("接收结束");
}catch(Exception e){
System.out.println("Error" + e);
}
}
public void run(){
try{
//由socket对象得到输入流,并构造相应的BufferedReader对象
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedReader sin = new BufferedReader(new InputStreamReader((System.in)));
String readline;
while(true){//一直循环 只要有消息就接收并且显示
readline = in.readLine(); //接收从Server得到的消息
if(readline.equals("sentfile")){
filepath = "D:\\360安全浏览器下载\\新建文本文档11.txt";
System.out.println("接收完毕");
ReceiveFile(socket,filepath);
}
System.out.println("other: " + readline);
}
}
catch(Exception e){
System.out.println("Error" + e);
}
}
}