特定将自己大二写的程序拿出来,因为实在没什么项目经验。当时也是在网上参考了些信息,不过自己也忘记是哪个博主的了,特此感谢之前的博主。接下来将这个程序的思路与源码分享给大家。里面有多多不足还请包涵。
完整的程序代码我将放在我的GitHub上,供大家下载。
GitHub完整源码
首先是服务器部分:
首先写一个服务器类继承JFrame用于可视化窗口。在类里面写以获得消息的函数getMessage。在getMessage里面启动信息传输线程。创建套接字不断接受来客户端的套接字。将新增加的客户端增加到列表中。代表如下:
public void getmessages()
{ //启动普通信息传输器
new PrintOutThread();
try {
ServerSocket server=null;
server=new ServerSocket(2559);
System.out.println("普通消息传输服务器"+2559);
String messages;
int i=0;
Socket s;
while(true)
{
s=server.accept();
//receiveFile(s);
thread_list.add(new ServerThread(s,i));
i++;
}
}
catch(Exception e)
{
System.err.println("发生异常:"+e);
e.printStackTrace();
}
}
客户端列表的定义如下:
private static List<ServerThread> thread_list = new ArrayList<ServerThread>();
接下来我们解析ServerThread类。
1,在类中定义int id,Socket socket两个变量。
2,为了接收和发出消息定义一个输入流一个输出流对象
private ObjectOutputStream m_output;//输出流
private ObjectInputStream m_input;//输入流
接下来则在创建构造函数包含套接字socket,id两个参数。
id是用来标准每个客户端的。在构造函数中获取获取套接字的输入输出流。并且启动线程。代码如下:
public ServerThread(Socket s,int i)
{
client = s;
id=i;
try
{
m_input=new ObjectInputStream(s.getInputStream());
m_output=new ObjectOutputStream(s.getOutputStream());
start();
}catch(Exception e)
{
e.printStackTrace();
}
}
接着我们查看run()函数里面的动作。
即我们不断获取来自客户端的消息,直到接收到客户端退出的消息。在接收消息时这里是将接收的消息全部放入消息队列当中,因为我们实现的是群聊。从而要实现一个客户端发完消息,服务器要将消息转发给除自己外,其他所有客户端。
代码如下:
public void run() {
// TODO Auto-generated method stub
try
{
String messages;
offLine=true;
while(offLine)
{
messages=m_input.readObject().toString();
if(messages.equals("!exit!"))
offLine=false;
message_list.add(new Message(id,messages));
isPrint=true;
}
m_output.flush();
m_output.close();
m_input.close();
client.close();
}catch(Exception e)
{
e.printStackTrace();
}
}
接下来我们就是讲下Message类,其实这个类主要是就是为了将消息绑上ID等等有发送线程发送就知道是谁的消息了。
public class Message {
private int ID;
private String msg;
public Message(int n,String m)
{
ID=n;
msg=m;
}
public int getName()
{
return ID;
}
public String getMsg()
{
return msg;
}
}
就下来就是服务器的最后一部分了。就是要开始发送消息了。在之前我们就已经启动了消息进程。直接在消息进程的run函数发送数据。首先对消息队列有个判断,若消息队列为空,则阻塞消息队列一段时间,目标为了将cpu让给其他线程。对与这一部分。大家可以去看下操作系统,cpu调度这一块。会给更加便于大家理解。接下来接收将消息队列取出消息。并且在服务器端队列取出各个来客户端的线程。判断若消息不是来自该客户端,若不是,则该服务器线程端发送给数据给该客户端。若是则不发送。代码如下:
public void run() {
while (true) {
//如果消息队列没有消息则暂停当前线程,把cpu片段让出给其他线程,提高性能
if (!isPrint) {
try {
Thread.sleep(500);
sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
continue;
}
// 将缓存在队列中的消息按顺序发送到各客户端,并从队列中清除。
Message msg = (Message)message_list.getFirst();
// 对所有的用户的线程遍历,如果不是自己发的消息就广播给其他人
for (int i = 0; i < thread_list.size(); i++) {
// 由于添加线程和用户是一起的,所以i所对应的用户就是i所对应的线程,可以根据这个判断是不是自己的线程
ServerThread thread = thread_list.get(i);
try {
if(i!=msg.getName())
thread.sendMessage(msg.getMsg());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
message_list.removeFirst();
isPrint = message_list.size() > 0 ? true : false;
}
最后一块大家看代码其实会更加清楚。这就是服务器的部分了。理解好服务器很重要。客户端相对来说就很好理解了。客户端我也上传到GitHub了,大家只需要上去下载就行了。过程就不说了。大家自己看看。