前几日写的一篇简陋之极的java聊天室被各位前辈说是,一塌糊涂,乌烟瘴气,只是简单的实现了需要的功能,并未做到人性化。在下痛定思痛,心想还是先学会显示功能再做美化界面,美化代码的打算!
在奋斗了一天之后终于完成了集图片,文字,直线等功能为一体的群聊天室。先分析代码如下:
关于界面什么的我就不说了,笔者在前面的博客中有提过!直接附上各种功能的实现方法。
首先我们要传送信息,必须要让被传送的对象知道我们传送的是什么东西,所以在传送信息之前,我们首先要确定一个协议,比如说当客户端接收到的第一个int 值为1的时候,它接下来就要再接收4个int值,据此来画一条直线,而我服务器画一条直线的时候可以获得该直线的四个int值,但是在利用IO流发送这四个int值的时候,我首先要先发送一个1,也就是说我每次在要发送一天直线之前就要先发送一个1,当然在客户端读取的时候,我们第一次读取到的是1,就接收四个int。当读完四个int之后并画完一条直线之后我们还要读取数据,如果还是1的话,我们继续上面的操作,如果读取的是2,按照规定的协议,我们就调用相应的方法即可!!!!
现附上服务器发送直线的代码如下,该代码是写在界面类里面的内部类:
//鼠标进入事件
MouseListener ms=(new MouseListener(){
public void mousePressed(MouseEvent e){
x1=e.getX();
y1=e.getY();
}
public void mouseReleased(MouseEvent e){
int x2=e.getX();
int y2=e.getY();
g.drawLine(x1,y1,x2,y2);
ChatTools.castbyte(1);
ChatTools.castbyte(x1);
ChatTools.castbyte(y1);
ChatTools.castbyte(x2);
ChatTools.castbyte(y2);
}
public void mouseClicked(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited (MouseEvent e){}
});
jp.addMouseListener(ms);
当然相应的我们也要在客户端定义一个读取数据的方法,首先我们要判断发送过来的是什么东西,我设置的协议是,如果首先读到的是1,接下来就画直线,如果读到的是2,接下来就接收一张图片,如果读到的是4,接下来读到的就是一段文字。该方法是放在客户端的线程中的,并且在线程的Run方法中调用该方法。
并且在每执行完一次操作之后,便再次读取一个int值,再次判断该int值为多少,以便得到下一个执行的指令。
public void processServer(Socket client){
try{
ins=client.getInputStream();
OutputStream out=client.getOutputStream();
dis = new DataInputStream(ins);
dout=new DataOutputStream(out);
int t=dis.readInt();
while(true){
//如果读到的是1,调用读取线段的方法
if(t==1){
readline();
}
//读到的是2则调用接受画面的方法
if(t==2){
readPic();
}
//如果读到的是4,则调用接受文字的方法
if(t==4){
readMsg();
}
t=dis.readInt();
}
}catch(Exception ef){
ef.printStackTrace();
}
}
当判断int值为1的时候,我们就调用画直线的方法,该方法如下
//定义一个读取线段的方法
public void readline() {
try {
int x1=dis.readInt();
int y1=dis.readInt();
int x2=dis.readInt();
int y2=dis.readInt();
g.drawLine(x1,y1,x2,y2);
} catch (IOException e) {
e.printStackTrace();
}
}
当然,我们需要在客户端和服务器都要定义相同功能的传送和接收方法。
现在我们再写一个文字的接收方法,首先我们会在文本输入框中输入字符,并获得该文本内容,每当按下发送这个按钮时便调用消息的传送方法,将该消息发送出去!
ActionListener al=(new ActionListener(){
public void actionPerformed(ActionEvent e){
String s=e.getActionCommand();
if(s.equals("创建")){
Chatserver cs=new Chatserver(9090,jta,dout,g);
cs.start();
}
//将服务器消息发给每个人
if(s.equals("发送")){
String msg=jte1.getText();
ChatTools.castMsg(msg);
jta.append("服务器说:"+msg+"\r\n");
jte1.setText("");
}
其中ChatTools.castMsg();是一个消息群发的方法,该方法在队列类里面定义的,代码如下
//将一个消息发送给所有人
public static void castMsg(String str){
ChatTools.castbyte(4);
for(int i=0;i<list.size();i++){
ServerThread st=list.get(i);
st.sendMs(i+"说:"+str);
}
}
而sendMsg();则是一个消息的发送方法。该方法如下
//将发送消息的代码包装到一个方法中
public void sendMs(String msg){
try{
msg+="\r\n";
dout.write(msg.getBytes());
//强制输出
dout.flush();
}catch(Exception ef){}
}
实现字符串传输的重中之重便是读取的方法,我们会首先获得一个为4的int值,然后我们就要调用字符串的读取方法
public void readMsg(){
try{
brd=new BufferedReader(new InputStreamReader(ins));
String input=brd.readLine();
jta.append(input +"\r\n");
}catch(Exception ef){}
}
我使用的BufferedReader缓冲流,实现整行读取的方式,该方式不会产生乱码,所以还是不错的。
而我今天要重点讲的便是图片从文件中读取和传送的方法。
首先我们要获得图片,再者我们要获取图片的宽度和高度,在循环遍历每个像素点,获取该点的颜色值,接着我们便在画布中调用画线的方法,依次画出每个像素点,并相应的给每个点附上相应的颜色即可。这样一张图片就在自己的画布上显示出来了!代码如下
ActionListener al=(new ActionListener(){
public void actionPerformed(ActionEvent e){
String s=e.getActionCommand();
if(s.equals("创建")){
Chatserver cs=new Chatserver(9090,jta,dout,g);
cs.start();
}
//将服务器消息发给每个人
if(s.equals("发送")){
String msg=jte1.getText();
ChatTools.castMsg(msg);
jta.append("服务器说:"+msg+"\r\n");
jte1.setText("");
}
if(s.equals("图片")){
try {
BufferedImage image = ImageIO.read(new File("2.jpg"));
int m=image.getHeight();
int n=image.getWidth();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
rgb=image.getRGB(i,j);
System.out.println(i);
System.out.println(j);
Color color=new Color(rgb);
g.setColor(color);
g.drawLine(i,j,i,j);
ChatTools.castbyte(2);
ChatTools.castbyte(rgb);
ChatTools.castbyte(i);
ChatTools.castbyte(j);
}
}
} catch (IOException e1) {
e1.printStackTrace();
}
能画出图片,当然我们就能发送图片,我们就能相应的读取图片,在发送图片信息的时候,我们每取出一个点,就能获得该店的颜色,我们就把该点横坐标和纵坐标以及颜色值发送过去。在接收端,我们会首先读到一个为2的int值,然后程序会调用图片的读取方法。方法如下
//图片的读取方法
public void readPic(){
int rgb;
try {
rgb = dis.readInt();
int i=dis.readInt();
int j=dis.readInt();
Color color =new Color(rgb);
g.setColor(color);
g.drawLine(i,j,i,j);
} catch (IOException e) {
e.printStackTrace();
}
}
值此,我们就实现了图片的发送功能了。我的代码也差不多了,至于如果有什么需要改进的地方请各位多多指教,本人是新手,迫切渴望成长,我也知道我的代码可定有很多漏洞,望不吝赐教!!!!!!!!!!!
现在附上具体的代码:服务器的四个类
界面类
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class MainServer {
private int x1;
private int y1;
private Graphics g;
private DataOutputStream dout;
private int rgb;
public void ShowUI(){
JFrame jf=new JFrame();
jf.setTitle(" 服务器");
jf.setSize(600,600);
jf.setLayout(null);
jf.setDefaultCloseOperation(3);
JButton jb=new JButton("创建");
jb.setBounds(0,0,60,30);
final JButton jm = new JButton("图片");// 实例化菜单栏的对象
jm.setBounds(70,0,60,30);
jf.add(jm);
JButton jb1=new JButton("发送");
jb1.setBounds(0,40,60,30);
final JTextField jte1=new JTextField(30);
jte1.setBounds(70,45,300,20);
final JTextArea jta=new JTextArea(20,30);
jta.setBounds(0,80,600,150);
final JPanel jp=new JPanel();
jp.setBounds(0,250,600,600);
jf.add(jb);
jf.add(jb1);
jf.add(jte1);
jf.add(jta);
jf.add(jp);
jf.setVisible(true);
jp.setBackground(Color.gray);
this.g=jp.getGraphics();
ActionListener al=(new ActionListener(){
public void actionPerformed(ActionEvent e){
String s=e.getActionCommand();
if(s.equals("创建")){
Chatserver cs=new Chatserver(9090,jta,dout,g);
cs.start();
}
//将服务器消息发给每个人
if(s.equals("发送")){
String msg=jte1.getText();
ChatTools.castMsg(msg);
jta.append("服务器说:"+msg+"\r\n");
jte1.setText("");
}
if(s.equals("图片")){
try {
BufferedImage image = ImageIO.read(new File("2.jpg"));
int m=image.getHeight();
int n=image.getWidth();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
rgb=image.getRGB(i,j);
System.out.println(i);
System.out.println(j);
Color color=new Color(rgb);
g.setColor(color);
g.drawLine(i,j,i,j);
ChatTools.castbyte(2);
ChatTools.castbyte(rgb);
ChatTools.castbyte(i);
ChatTools.castbyte(j);
}
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
});
jm.addActionListener(al);
jb.addActionListener(al);
jb1.addActionListener(al);
//鼠标进入事件
MouseListener ms=(new MouseListener(){
public void mousePressed(MouseEvent e){
x1=e.getX();
y1=e.getY();
}
public void mouseReleased(MouseEvent e){
int x2=e.getX();
int y2=e.getY();
g.drawLine(x1,y1,x2,y2);
ChatTools.castbyte(1);
ChatTools.castbyte(x1);
ChatTools.castbyte(y1);
ChatTools.castbyte(x2);
ChatTools.castbyte(y2);
}
public void mouseClicked(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited (MouseEvent e){}
});
jp.addMouseListener(ms);
}
public static void main(String[] args){
MainServer ms=new MainServer();
ms.ShowUI();
}
}
处理客户机连接的两个线程类
import java.awt.Graphics;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JTextArea;
public class Chatserver extends Thread{
private Graphics g;
private int port;
private JTextArea jta;
private DataOutputStream dout;//输出流
private ServerSocket ss;
public Chatserver(int port,JTextArea jta,DataOutputStream dout,Graphics g){
this.port=port;
this.jta=jta;
this.dout=dout;
this.g=g;
}
public void run(){
setUpServer(port);
}
//在指定端口上创建一个服务器
public void setUpServer(int port){
try{
ss = new ServerSocket(port);
System.out.println("服务器创建成功");
//等待客户机连接,并设置成循环等待状态
while(true){
Socket client=ss.accept();
System.out.println("欢迎进入我的服务器");
//启动一个线程去处理该对象
ServerThread st=new ServerThread(client,jta,dout,g);
st.start();
ChatTools.add(st);
ChatTools.castMsg("有人上线!!目前在线人数"+ChatTools.getsize());
}
}catch(Exception ef){
ef.printStackTrace();
}
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import javax.swing.JTextArea;
public class ServerThread extends Thread{
private Socket client;//线程中处理的客户对象
private DataOutputStream dout;//输出流
private OutputStream out;//输出流
private DataInputStream dis;//
private JTextArea jta;
private BufferedReader brd;
private InputStream ins;
//创建线程对象时要传入他要处理的连接对象
private Graphics g;
public ServerThread(Socket client,JTextArea jta,DataOutputStream dout,Graphics g){
this.client=client;
this.jta=jta;
this.dout=dout;
this.g=g;
}
public void readMsg(){
try{
brd=new BufferedReader(new InputStreamReader(ins));
String input=brd.readLine();
jta.append("客户说:"+input +"\r\n");
ChatTools.castMsg(input);
}catch(Exception ef){}
}
//将发送消息的代码包装到一个方法中
public void sendMs(String msg){
try{
msg+="\r\n";
dout.write(msg.getBytes());
//强制输出
dout.flush();
}catch(Exception ef){}
}
public void run(){
//在线程中 调用处理链接的方法
processChat(this.client);
}
//处理客户机进入的连接对象
public void processChat(Socket client){
try{
ins=client.getInputStream();
out=client.getOutputStream();
dis = new DataInputStream(ins);
dout=new DataOutputStream(out);
int t=dis.readInt();
while(true){
if(t==1){
readline();
}
if(t==2){
readPic();
}
if(t==4){
readMsg();
}
t=dis.readInt();
}
}catch(Exception ef){
ef.printStackTrace();
}
}
//发送int型值得方法
public void sendbyte(int x1){
try{
dout.writeInt(x1);
dout.flush();
}catch(Exception e){}
}
//图片的读取方法
public void readPic(){
int rgb;
try {
rgb = dis.readInt();
int i=dis.readInt();
int j=dis.readInt();
Color color =new Color(rgb);
g.setColor(color);
g.drawLine(i,j,i,j);
} catch (IOException e) {
e.printStackTrace();
}
}
//定义一个读取线段的方法
public void readline() {
try {
int x1=dis.readInt();
int y1=dis.readInt();
int x2=dis.readInt();
int y2=dis.readInt();
g.drawLine(x1,y1,x2,y2);
} catch (IOException e) {
e.printStackTrace();
}
}
}
一个队列类,用来存储连接进服务器的客户机对象类
import java.util.ArrayList;
import java.util.List;
public class ChatTools {
//保存处理线程的队列对象
static List<ServerThread> list=new ArrayList<ServerThread>();
private ChatTools(){
}//不需要创建引类对象,构造器则私有
//取得保存保存处理线程对象的队列
public static List<ServerThread> getAllthread(){
return list;
}
//将一个客户对应的处理线程对象加入到队列中
public static void add(ServerThread st){
//通知有人上线了
list.add(st);
}
public static int getsize(){
int i=list.size();
return i;
}
//将一个消息发送给所有人
public static void castMsg(String str){
ChatTools.castbyte(4);
for(int i=0;i<list.size();i++){
ServerThread st=list.get(i);
st.sendMs(i+"说:"+str);
}
}
//定义一个字节群发的方法
public static void castbyte(int x1){
for(int i=0;i<list.size();i++){
ServerThread st=list.get(i);
st.sendbyte(x1);
}
}
}
接下来便是客户机的两个类
界面类
package 多人聊天室客户端;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Mainchat {
private MainchatThread mt;
private Graphics g;
private int x1;
private int y1;
private InputStream ins;
private int rgb;
public void ShowUI(){
JFrame jf=new JFrame();
jf.setTitle(" 客户机");
jf.setSize(600,500);
jf.setLocation(700,0);
jf.setLayout(null);
jf.setDefaultCloseOperation(3);
JButton jb=new JButton("连接");
jb.setBounds(0,0,60,30);
final JButton jm = new JButton("图片");// 实例化菜单栏的对象
jm.setBounds(70,0,60,30);
jf.add(jm);
JButton jb1=new JButton("发送");
jb1.setBounds(0,40,60,30);
final JTextField jte1=new JTextField(30);
jte1.setBounds(70,45,300,20);
final JTextArea jta=new JTextArea(20,30);
jta.setBounds(0,80,600,150);
JPanel jp=new JPanel();
jp.setBounds(0,250,600,400);
jf.add(jb);
jf.add(jb1);
jf.add(jte1);
jf.add(jta);
jf.add(jp);
jf.setVisible(true);
jp.setBackground(Color.gray);
this.g=jp.getGraphics();
ActionListener al=(new ActionListener(){
public void actionPerformed(ActionEvent e){
String s=e.getActionCommand();
if(s.equals("连接")){
try {
mt=new MainchatThread("localhost",9090,jta,g,ins);
if(mt.runing()){
mt.start();
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
//将消息发给别人
if(s.equals("发送")){
String msg=jte1.getText();
jta.append("我说:"+msg+"\r\n");
MainchatThread.sendbyte(4);
mt.sendMsg(msg);
System.out.println("消息已经发送");
jte1.setText("");
}
if(s.equals("图片")){
try {
BufferedImage image = ImageIO.read(new File("2.jpg"));
int m=image.getHeight();
int n=image.getWidth();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
rgb=image.getRGB(i,j);
System.out.println(i);
System.out.println(j);
Color color=new Color(rgb);
g.setColor(color);
g.drawLine(i,j,i,j);
MainchatThread.sendbyte(2);
MainchatThread.sendbyte(rgb);
MainchatThread.sendbyte(i);
MainchatThread.sendbyte(j);
}
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
});
jm.addActionListener(al);
jb.addActionListener(al);
jb1.addActionListener(al);
jf.setVisible(true);
MouseListener ms=(new MouseListener(){
public void mousePressed(MouseEvent e){
x1=e.getX();
y1=e.getY();
System.out.println(x1);
}
public void mouseReleased(MouseEvent e){
int x2=e.getX();
int y2=e.getY();
g.drawLine(x1,y1,x2,y2);
MainchatThread.sendbyte(1);
MainchatThread.sendbyte(x1);
MainchatThread.sendbyte(y1);
MainchatThread.sendbyte(x2);
MainchatThread.sendbyte(y2);
}
public void mouseClicked(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited (MouseEvent e){}
});
jp.addMouseListener(ms);
}
public static void main(String[] args){
Mainchat ms=new Mainchat();
ms.ShowUI();
}
}
线程类,用来运行客户机读取服务器发来的信息
package 多人聊天室客户端;
import java.awt.Color;
import java.awt.Graphics;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import javax.swing.JTextArea;
public class MainchatThread extends Thread{
private static DataOutputStream dout;
private InputStream ins;
private BufferedReader brd;
private int port;
private String ip;
private JTextArea jta;
private Graphics g;
private DataInputStream dis;
private Socket socket;
public MainchatThread(String ip,int port,JTextArea jta,Graphics g,InputStream ins){
this.jta=jta;
this.ip=ip;
this.port=port;
this.g=g;
this.ins=ins;
}
public boolean runing(){
try{
socket=new Socket(this.ip,this.port);
System.out.println("连接成功");
InputStream ins=socket.getInputStream();
OutputStream out=socket.getOutputStream();
dis=new DataInputStream(ins);
dout=new DataOutputStream(out);
return true;
}catch (Exception e){
e.printStackTrace();
}return false;
}
//图片的读取方法
public void readPic(){
int rgb;
try {
rgb = dis.readInt();
int i=dis.readInt();
int j=dis.readInt();
Color color =new Color(rgb);
g.setColor(color);
g.drawLine(i,j,i,j);
} catch (IOException e) {
e.printStackTrace();
}
}
//发送信息
public void sendMsg(String msg){
try{
msg+="\r\n";
dout.write(msg.getBytes());
dout.flush();
}catch(Exception ef){}
}
public static void sendbyte(int i){
try{
dout.writeInt(i);
dout.flush();
}catch(Exception ef){}
}
//读取服务端信息的方法
public void readMsg(){
try{
brd=new BufferedReader(new InputStreamReader(ins));
String input=brd.readLine();
jta.append(input +"\r\n");
}catch(Exception ef){}
}
public void readline(){
try{
int x1=dis.readInt();
int y1=dis.readInt();
int x2=dis.readInt();
int y2=dis.readInt();
g.drawLine(x1,y1,x2,y2);
}catch(Exception ef){}
}
public void processServer(Socket client){
try{
ins=client.getInputStream();
OutputStream out=client.getOutputStream();
dis = new DataInputStream(ins);
dout=new DataOutputStream(out);
int t=dis.readInt();
while(true){
//如果读到的是1,调用读取线段的方法
if(t==1){
readline();
}
//读到的是2则调用接收图片的方法
if(t==2){
readPic();
}
//如果读到的是4,则调用接受文字的方法
if(t==4){
readMsg();
}
t=dis.readInt();
}
}catch(Exception ef){
ef.printStackTrace();
}
}
public void run(){
processServer(socket);
}
}
至此完结!!!