您的位置:首页 > 其它

简单的聊天应用,分析线程问题

2015-06-18 16:06 369 查看
1.服务器端

package javaQQ;

import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

public class JavaQserver {
//建立客户端线程集合,便于群发
ArrayList<ClientTread> array=new ArrayList<ClientTread>();
//定义全局用户变量
String name="";
public void Start(){
ServerSocket qqserver;
try {
qqserver=new ServerSocket(3300);
System.out.println("服务器启动了");
while(true){
//阻塞 等待客户端的访问,返回套接字。
Socket qq=qqserver.accept();
//读取客户端传来的名字
name=redDate(qq);
System.out.println(name+"-->客户端在线");
//创建服务器聊天记录
//OutputText(qq);
//实例化客户端线程
ClientTread clientTread=new ClientTread(qq);
//启动线程
new Thread(clientTread).start();
array.add(clientTread);
}
} catch (IOException e) {
e.printStackTrace();
}
}

//显示时间fun
public String ShowTime(){
//获取时间
Date rightNow = new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String data=sdf.format(rightNow);
return data;
}
//读取套接字fun 输入流
public String redDate(Socket data){
InputStream in;
try {
in = data.getInputStream();
byte[] buf=new byte[1024];
int len=in.read(buf);
String getstr=new String(buf,0,len);
return getstr;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

//线程
class ClientTread implements Runnable{
Socket e;
InputStream in;
OutputStream out;
boolean isConnect=false;//判断是否和服务器相连
public ClientTread(Socket e) {
this.e=e;
try {
in=e.getInputStream();
out=e.getOutputStream();
isConnect=true;
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
@Override
public void run() {//读取一个线程套接字
while (isConnect) {
try {
byte[] buf=new byte[1024];
int len=in.read(buf);
String getstr=new String(buf,0,len);
if("seeyou".equals(getstr)){
isConnect=false;
array.remove(this);
}else {
System.out.println(ShowTime()+"\n"+getstr);
//发送数据给所有用户
for(int i=0;i<array.size();i++){
ClientTread ct=array.get(i);
ct.send(ShowTime()+"\n" +getstr);
}

}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

//线程内写入套接字
public void send(String input){
try {
out.write(input.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
JavaQserver s1=new JavaQserver();
s1.Start();
}
}


我这里为什么,在套接字读取的线程呢!下面是我的分析
首先:实例化了一个ServerSocket,接收客户端的套接字,当服务器端运行是开启一个线程来接收 客户端的数据,

假想一下,如果没有线程呢!客户端的套接字,在while循环中。。。。当主线程运行完,能接收另一个客户端,你有没有发现一个客户端

只能传一次数据,而且每个客户端传来的数据都是如此。(做完才能执行下一步)

所有:当传入数据时,我开启了一个线程,这个线程没完就一直做下去。不影响其他客户端(有线程帮他执行)

2.客户端

我想客户端的的线程也是这个原理把

package javaQQ;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

import javax.swing.*;

@SuppressWarnings("serial")
public class JavaQclient extends Frame{
//单行文本控件
TextField txtIput=new TextField();
//多行文本控件
TextArea txtDinput=new TextArea();
//定义输入,输出流全局变量
OutputStream out;
InputStream in;
//定义全局的 套接字实现连接服务器
Socket socket;
//定义一个判断是否连接
boolean isClient;
//用户名
final String name;
public JavaQclient() {
//弹出输入框,输入用户姓名
name=JOptionPane.showInputDialog(" 请输入姓名:");
//设置窗体名
setTitle("QQ原型---"+name);
//设置窗体大小
setSize(300, 400);
//设置初现位置,,,居中
setLocationRelativeTo(null);
///窗体是否可变,
setResizable(false);
//窗体是否可视
setVisible(true);
//添加控件,BorderLayout为布局。
add(txtIput,BorderLayout.SOUTH);
add(txtDinput,BorderLayout.NORTH);
pack();//自动调整组件大小
//设置记录框只读
txtDinput.setEditable(false);
//添加窗体监听事件
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
sendDate("seeyou");
isClient=false;
System.exit(0);
}

});
init();//输入流和输出流的初始化

//把聊天者的名字传给服务器记录
sendDate(name);

//输入框的动作监听事件
txtIput.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
//得到输入框的内容
String input=txtIput.getText();
//聊天内容发送给服务器
sendDate(name+":"+input);
txtIput.setText("");
}
});
}
//定义接收数据的线程
class ServerThread implements Runnable{
@Override
public void run() {
byte[] buf=new byte[1024];
try {
while (isClient) {
int len = in.read(buf);
String getstr=new String(buf,0,len);
txtDinput.append(getstr+"\n");
RecordText(getstr+"\n");
}

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

//发送数据到服务器
public void sendDate(String data){
try {
out.write(data.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

//聊天记录文件记录写入
public void RecordText(String str){
FileWriter file;
try {
file=new FileWriter(name+".txt",true);
BufferedWriter out=new BufferedWriter(file);
out.write(str);
out.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//聊天记录文件记录读取
public void OutputText(){
File file = new File(name+".txt");
String outText="";
try {
if(!file.exists()){
file.createNewFile();
}else {
FileReader inputStream=new FileReader(file);
char[] buf = new char[1024];
int len = inputStream.read(buf); //读buf.length个字节到缓存
while(len != -1){
for (char i:buf){
outText=outText+i;
}
txtDinput.append(outText);
len = inputStream.read(buf); //继续读取后面的字节
}
inputStream.close();
}

} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

//实例花socket对象
public void init(){
try {
//实例花socket对象
socket = new Socket("127.0.0.1",3300);
//得到套接字的输入输出流
out=socket.getOutputStream(); //输出数据流
in=socket.getInputStream();//输入数据流
OutputText();//读取聊天记录
isClient=true;
new Thread(new ServerThread()).start();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//开启客户端

}

public static void main(String[] args) {
new JavaQclient();
}
}


如果有分析的不对的地方,还请广大网友指正
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  聊天 线程 socket