您的位置:首页 > 编程语言 > Java开发

最基础的java socket聊天程序应该烂熟于心

2014-02-09 17:15 363 查看
过年在家有大把的闲暇时间,无聊的时候把这个socket聊天程序反复敲了几次,尽量弄懂每个细节,应该对以后继续深入学习socket编程和多线程编程有帮助。

下面这个socket聊天程序的例子主要分为三个部分和N个容器。

1.需要一个继承SocketServer的服务器类 Server。

2.需要一个继承Thread的客服端类 Client。

3.需要一个消息处理类(广播类)处理每个Client产生的聊天记录。

然后还需要多个全局的容器:一个消息队列,负责储存所有Client产生的消息;一个Thread队列,记录加入到server的所有client线程。



具体代码如下:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.LinkedList;

/**
* User: Administrator
* Date: 14-1-29
* Time: 下午7:40
*/
public class Server extends ServerSocket{
private FileOutputStream serverLogs = new FileOutputStream("D:/connect.log",true);
private static final int PORT = 18888; //指定server端 端口号
private static LinkedList<String> messageHandler = new LinkedList<String>(); //存放消息的队列
private static ArrayList<Client> threads = new ArrayList<Client>();//存放client线程
private static ArrayList<String> nikeNameList = new ArrayList<String>();//存放nikeName
private static boolean isClean = true;
public Server() throws Exception{
super(PORT);
//启动消息管理线程
new MessageHandler();
//记录服务端启动日志
Calendar calendar = Calendar.getInstance();
byte[] logs = (calendar.getTime().toString()+"server is start.").getBytes();
serverLogs.write(logs);
//响应client连接请求,把socket对象放客户端线程
try {
while(true){
Socket socket = accept();
new Client(socket);
}
} finally {
close();
}

}

public static void main(String[] args) throws Exception{
new Server();
}

class MessageHandler extends Thread{

public MessageHandler(){
start();
}

public void run(){
while(true){
if(!isClean){
String message = messageHandler.getLast();
for(Client client:threads){
client.pushMessages(message);
}
isClean = true;
}
// isClean = true; 这句不能写在这里,想想为什么?

}
}
}
class Client extends Thread{
private BufferedReader in;
private PrintWriter out ;
private String nikeName;
private String input;
private Socket clientSocket;
public Client(Socket client) throws Exception{
this.clientSocket = client;
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
out = new PrintWriter(clientSocket.getOutputStream(),true);
out.println("------------welcome-------------");
out.println("please input your nikeName:");
start();
}
@Override
public void run() {
try {
input = in.readLine();
nikeName = input;
int count = 0;
while (!"bye".equals(input)){
if(count++ == 0){
out.println("ok,welcome<"+nikeName+">,you can talk now.");
nikeNameList.add(nikeName);
threads.add(this);
messageHandler.addLast("<" + nikeName + "> entered the chartRoom.");
}else {
if("L".equals(input)){
showAllUsers();
}else {
pullMessages("<"+nikeName+">:"+input);
}

}
input = in.readLine();
}
out.println("bye <"+nikeName+">");
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//pullMessages("<"+nikeName+"> is left the room."); 这句不能写在这里,呵呵,想想为什么?
nikeNameList.remove(nikeName);
threads.remove(this);
in.close();
out.close();
if(!clientSocket.isClosed()){
clientSocket.close();
}
pullMessages("<"+nikeName+"> is left the room."); //应该写在这里
} catch (IOException e) {
e.printStackTrace();
}
}
}

//向当前线程展示所有在线用户
public void showAllUsers(){
out.println("------show all users-------");
for(String name : nikeNameList){
out.println("<"+name+"> is online.");
}
out.println("---------------------------");
}

//把当前线程的消息放入消息队列
public void pullMessages(String message){
messageHandler.addLast(message);
isClean = false;
}

//推送消息
public void pushMessages(String message){
out.println(message);
}
}
}

打开CMD 输入 telnet localhost 18888 会产生一个连接到server的client线程,输入昵称后就可以开始聊天了(可以打开多个,然后自己和自己聊天)。
上面的程序实现了如下功能:记录服务器启动日志,多线程聊天。查看当前进入聊天室的人列表。 如果感兴趣还可以加入查看聊天记录,显示聊天时间等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java socket 多线程