最近学完网络线程协议 ,因此写了一个用java编写的聊天室 话不多说
效果如图
package com.yc.server;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Type;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.yc.bean.JsonModel;
import com.yc.bean.User;
import com.yc.bean.YcConstants;
public class TalkServer {
private List list=new ArrayList();
public static void main(String[] args) throws IOException {
TalkServer ts=new TalkServer();
ts.startServer();
}
public void startServer() throws IOException{
ServerSocket ss=new ServerSocket(9998);
System.out.println("服务器"+ss.getInetAddress()+"启动了,监听了:"+ss.getLocalPort()+"端口");
while(true){
Socket s=ss.accept();
System.out.println("客户端"+ss.getInetAddress()+"联接上了服务器");
//将这个s存到一个TalkService中,做成一个线程,处理一个与客户端的联接
ClientSocket cs=new ClientSocket(s);
Thread t=new Thread(cs);
t.start();
}
}
//内部类:实现了Runnable接口的内部类,用于封装对一个客户端的操作
class ClientSocket implements Runnable{ //不写外部类是因为都要操作这个list,写外部类传这个list较为麻烦
private Socket s;
private Scanner sc;
private PrintWriter pw;
private boolean flag=false;
private String nickname;
private String ip;
public ClientSocket(Socket s){
this.s=s;
System.out.println("客户端"+s.getInetAddress()+"连接上了服务器");
if(s!=null){
try {
sc=new Scanner(s.getInputStream());
pw=new PrintWriter(s.getOutputStream());
flag=true;
} catch (IOException e) {
e.printStackTrace();
System.out.println("客户端"+s.getInetAddress()+"掉线了");
list.remove(ClientSocket.this);
flag=false;
sc.close();
pw.close();
try {
s.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
@Override
public void run() {
while(flag){
//读取用户传过来的消息
if(sc.hasNextLine()){
String jsonline=sc.nextLine();
parseProtocal(jsonline);
}
}
}
//解析状态码
private int parseCode(String jsonline){
if(jsonline.startsWith("{\"code\":1,")){
return 1;
}else if(jsonline.startsWith("{\"code\":3,")){
return 3;
}else if(jsonline.startsWith("{\"code\":4,")){
return 4;
}
return 404;
}
//发送信息到客户端
private void sendMsgToAllClient(String jsonline){
for(ClientSocket cs:list){
cs.pw.println(jsonline);
cs.pw.flush(); //必须flush()
}
}
//解析协议
private void parseProtocal(String jsonline) {
//判断code的值
int code=parseCode(jsonline);
if(code==1){
//1是普通聊天信息,直接向所有的客户端广播
sendMsgToAllClient(jsonline);
}else if(code==3){
//如果是3,表明有新用户登录
Gson g=new Gson();
Type type=new TypeToken>(){}.getType();
JsonModel jsonModel=g.fromJson(jsonline, type);
//将这个User存入到list中
User loginuser=jsonModel.getT();
List userlist=new ArrayList();
//将新登录的用户存入到list中
ClientSocket.this.ip=loginuser.getIp();
ClientSocket.this.nickname=loginuser.getNickname();
list.add(ClientSocket.this);
for(ClientSocket cs:list){
User u=new User();
u.setIp(cs.ip);
u.setNickname(cs.nickname);
userlist.add(u);
}
sendUserListJson(userlist);
}else if(code==4){
//如果是code为4,则要从ClientSocket中删除这个用户
Gson g=new Gson();
Type type=new TypeToken>(){}.getType();
JsonModel jsonModel=g.fromJson(jsonline, type);
List userlist=new ArrayList();
list.remove(ClientSocket.this);
for(ClientSocket cs:list){
User u=new User();
u.setIp(cs.ip);
u.setNickname(cs.nickname);
userlist.add(u);
}
sendUserListJson(userlist);
}
}
//发送用户列表的json字符串
public void sendUserListJson(List userlist){
String jsonline;
JsonModel> jm=new JsonModel>();
jm.setCode(YcConstants.SEND_USERLIST);
jm.setT(userlist);
Type t=new TypeToken>(){}.getType();
Gson g=new Gson();
jsonline=g.toJson(jm,t);
for(ClientSocket cs:list ){
cs.pw.println(jsonline);
cs.pw.flush();
}
}
}
}
客户端
package com.yc.client;
import java.io.IOException;
public class TalkClient implements Runnable{
protected Shell shell;
private Text txtCat;
private Text txtLocalhost;
private Text text_2;
private Text text_3;
private Table table;
private Button button;
private Button button_1;
private Button button_2;
private Text text_4;
private Socket s;
private Scanner sc;
private PrintWriter pw;
private String nickname;
private boolean flag=false;
/**
* Launch the application.
* @param args
*/
public static void main(String[] args) {
try {
TalkClient window = new TalkClient();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Open the window.
*/
public void open() {
Display display = Display.getDefault();
createContents();
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
/**
* Create contents of the window.
*/
protected void createContents() {
shell = new Shell();
shell.setSize(744, 671);
shell.setText("SWT Application");
shell.setLayout(new FillLayout(SWT.HORIZONTAL));
SashForm sashForm = new SashForm(shell, SWT.NONE);
sashForm.setOrientation(SWT.VERTICAL);
Composite composite = new Composite(sashForm, SWT.NONE);
composite.setLayout(new FillLayout(SWT.HORIZONTAL));
Group group = new Group(composite, SWT.NONE);
group.setText("登录");
Label label = new Label(group, SWT.NONE);
label.setBounds(21, 26, 36, 17);
label.setText("昵称:");
txtCat = new Text(group, SWT.BORDER);
txtCat.setText("cat");
txtCat.setBounds(57, 23, 122, 23);
Label lblip = new Label(group, SWT.NONE);
lblip.setBounds(233, 26, 59, 17);
lblip.setText("服务器IP:");
txtLocalhost = new Text(group, SWT.BORDER);
txtLocalhost.setText("localhost");
txtLocalhost.setBounds(292, 23, 122, 23);
Label label_2 = new Label(group, SWT.NONE);
label_2.setBounds(459, 26, 36, 17);
label_2.setText("端口:");
text_2 = new Text(group, SWT.BORDER);
text_2.setText("9998");
text_2.setBounds(496, 23, 104, 23);
button = new Button(group, SWT.NONE);
button.setBounds(448, 61, 80, 27);
button.setText("登录");
button_1 = new Button(group, SWT.NONE);
button_1.setBounds(574, 61, 80, 27);
button_1.setText("断开");
Composite composite_1 = new Composite(sashForm, SWT.NONE);
composite_1.setLayout(new FillLayout(SWT.HORIZONTAL));
Group group_1 = new Group(composite_1, SWT.NONE);
group_1.setText("聊天记录");
group_1.setLayout(new FillLayout(SWT.HORIZONTAL));
SashForm sashForm_1 = new SashForm(group_1, SWT.NONE);
Composite composite_3 = new Composite(sashForm_1, SWT.NONE);
composite_3.setLayout(new FillLayout(SWT.HORIZONTAL));
text_3 = new Text(composite_3, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
Composite composite_4 = new Composite(sashForm_1, SWT.NONE);
composite_4.setLayout(new FillLayout(SWT.HORIZONTAL));
table = new Table(composite_4, SWT.BORDER | SWT.FULL_SELECTION);
table.setHeaderVisible(true);
table.setLinesVisible(true);
TableColumn tableColumn = new TableColumn(table, SWT.NONE);
tableColumn.setWidth(121);
tableColumn.setText("用户昵称");
TableColumn tblclmnIp = new TableColumn(table, SWT.NONE);
tblclmnIp.setWidth(134);
tblclmnIp.setText("IP");
sashForm_1.setWeights(new int[] {448, 271});
Composite composite_2 = new Composite(sashForm, SWT.NONE);
composite_2.setLayout(new FillLayout(SWT.HORIZONTAL));
Group group_2 = new Group(composite_2, SWT.NONE);
group_2.setText("发送内容");
text_4 = new Text(group_2, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
text_4.setBounds(52, 32, 476, 105);
Label label_3 = new Label(group_2, SWT.NONE);
label_3.setBounds(10, 35, 36, 17);
label_3.setText("内容:");
button_2 = new Button(group_2, SWT.NONE);
button_2.setBounds(570, 110, 80, 27);
button_2.setText("发送");
sashForm.setWeights(new int[] {97, 378, 152});
//发送
button_2.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
String message=text_4.getText().trim().toString();
if(message==null || message.length()<0||"".equals(message)){
MessageDialog.openError(shell, "出错了", "要发送的信息不能为空");
return;
}
JsonModel jsonModel=new JsonModel();
jsonModel.setCode(YcConstants.SEND_MESSAGE);
Content c=new Content();
c.setNickname(nickname);
c.setIp(s.getLocalAddress().toString());
c.setMsg(message);
jsonModel.setT(c);
//将jsonModel对象转成json字符串,通过gson转
//通过TypeToken对象,向Gson来说明这个泛型类的构成
Gson g=new Gson();
Type type=new TypeToken>(){}.getType();
String jsonstring=g.toJson(jsonModel,type);
pw.println(jsonstring);
pw.flush();
text_4.setText("");
}
});
//断开
button_1.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if(s==null){
return;
}
JsonModel jsonModel=new JsonModel();
jsonModel.setCode(YcConstants.USER_LOGIN_OUT_CODE);
User user=new User();
user.setNickname(nickname);
user.setIp(s.getLocalAddress().toString());
jsonModel.setT(user);
//将jsonModel对象转成json字符串,通过gson转
//通过TypeToken对象,向Gson来说明这个泛型类的构成
Gson g=new Gson();
Type type=new TypeToken>(){}.getType();
String jsonstring=g.toJson(jsonModel,type);
pw.println(jsonstring);
pw.flush();
//退出
String content=text_3.getText();
Date d=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
content="\n"+nickname+"退出聊天\n\t\t\t\t"+sdf.format(d)+content;
text_3.setText(content);
pw.close();
sc.close();
try {
s.close();
s=null;
txtCat.setEnabled(true);
txtLocalhost.setEnabled(true);
text_2.setEnabled(true);
button.setEnabled(true);
button_1.setEnabled(false);
button_2.setEnabled(false);
flag=false;
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
//登录
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
nickname=txtCat.getText().toString();
String ip=txtLocalhost.getText().toString();
String port=text_2.getText().toString();
int p=Integer.parseInt(port);
try {
s=new Socket(ip, Integer.parseInt(port));
sc=new Scanner(s.getInputStream());
pw=new PrintWriter(s.getOutputStream());
txtCat.setEnabled(false);
txtLocalhost.setEnabled(false);
text_2.setEnabled(false);
button.setEnabled(false);
button_1.setEnabled(true);
button_2.setEnabled(true);
JsonModel jsonModel=new JsonModel();
jsonModel.setCode(YcConstants.USER_LOGIN_CODE);
User user=new User();
user.setNickname(nickname);
user.setIp(s.getLocalAddress().toString());
jsonModel.setT(user);
//将jsonModel对象转成json字符串,通过gson转
//通过TypeToken对象,向Gson来说明这个泛型类的构成
Gson g=new Gson();
Type type=new TypeToken>(){}.getType();
String jsonstring=g.toJson(jsonModel,type);
pw.println(jsonstring);
pw.flush();
flag=true;
Thread t=new Thread(TalkClient.this);
t.start();
} catch (Exception e1) {
e1.printStackTrace();
MessageDialog.openError(shell, "出错了", e1.getMessage());
txtCat.setEnabled(true);
txtLocalhost.setEnabled(true);
text_2.setEnabled(true);
button.setEnabled(true);
button_1.setEnabled(false);
button_2.setEnabled(false);
}
}
});
}
@Override
public void run() {
//不断的接收服务器的响应
while( flag ){ //当flag==true
//接收服务器的回传数据
if(s!=null&&s.isClosed()==false&&sc!=null&&sc.hasNextLine()){
String jsonline=sc.nextLine();
//解析协议
parseProtocal(jsonline);
}
}
}
private void parseProtocal(String jsonline) {
//判断code的值
int code=parseCode(jsonline);
if(code==1){
//如果code==1,则t是content对象,则操作文本显示聊天信息
Gson g=new Gson();
Type type=new TypeToken>(){}.getType();
JsonModel jsonModel=g.fromJson(jsonline,type);
final Content c=jsonModel.getT();
Display.getDefault().asyncExec(new Runnable(){
@Override
public void run() {
Date d=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String txt=text_3.getText().trim();
String msg="\n\n"+c.getNickname()+"对大家说:\n"+c.getMsg()+"\n\t\t\t\t发表时间"+sdf.format(d)+"\n";
txt=msg+txt;
text_3.setText(txt);
}
});
}else if(code==2){
//如果code==2,则t是userlist集合对象,则更新table
Gson g=new Gson();
Type type=new TypeToken>>(){}.getType();
JsonModel> jsonModel=g.fromJson(jsonline,type);
final List list=jsonModel.getT();
Display.getDefault().asyncExec(new Runnable(){
@Override
public void run() {
table.removeAll();
for(User u:list){
TableItem ti=new TableItem(table,SWT.None);
ti.setText(new String[]{u.getNickname(),u.getIp()});
}
}
});
}
}
private int parseCode(String jsonline) {
if(jsonline.startsWith("{\"code\":1,")){
return 1;
}else if(jsonline.startsWith("{\"code\":2,")){
return 2;
}
return 404;
}
}
其他辅助类 包括聊天人的个人信息和说的内容
package com.yc.bean;
public class Content {
private String nickname;
private String ip;
private String msg;
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return ip+"\t"+nickname+"\t"+msg;
}
}
package com.yc.bean;
public class JsonModel {
private int code;
private T t;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
package com.yc.bean;
//登录或退出的用户信息
public class User {
private String nickname;
private String ip;
public User() {
super();
}
public User(String nickname, String ip) {
super();
this.nickname = nickname;
this.ip = ip;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
}
package com.yc.bean;
public class YcConstants {
//登录的code值为3
public static final int USER_LOGIN_CODE=3;
//退出的code值值为4
public static final int USER_LOGIN_OUT_CODE=4;
//发送信息的code值为1
public static final int SEND_MESSAGE=1;
//发送用户列表的code值为2
public static final int SEND_USERLIST=2;
}