接触Socket没多长时间,自己想模拟实现一个聊天程序,因此写出了这个原型。因为所有这些想法都是自己单独想出来的,也没有上网查实现一个聊天的程序应当怎么弄,所以其中肯定有很多不理想的地方。本身的目的只是为了熟悉一下Socket与多线程编程,所以如果觉得程序哪不好感谢各位赐教。
1. Server.java:做为一个中转站,接收来自各个用户线程传输过来的消息,然后将其发送到相应的目的地。
package com.icarusliu.learn.chart.test3;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server implements Runnable {
private ServerSocket server;
// 服务器信息
private static final int serverPort = 9001;// 端口是一定的
public Server() {
try {
server = new ServerSocket(serverPort);// 启动服务
} catch (IOException ex) {
System.out.println("Server-Error:cannot init the Server!");
}
}
public void run() {
System.out.println("Server-Server started!");
// 如果有用户请求,那么为用户配一个用户线程
while (true) {
try {
Socket socket = server.accept();
UserThread t = new UserThread(socket);
Thread ut = new Thread(t);
ut.start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
/**
* 用户线程,每个用户线程包括一个消息,一个接受线程,一个发送线程
*
* @author Administrator
*
*/
class UserThread implements Runnable {
private Message message;//共用一个消息存储
private SendThread sendThread;//发送线程
private ReceiveThread receiveThread;//接收线程
private Socket socket;
public UserThread(Socket socket) {
this.socket = socket;
message = new Message();
}
public void run() {
System.out.println("Server-User:"
+ socket.getInetAddress().getHostAddress() + "("
+ socket.getPort() + ") connected!");
receiveThread = new ReceiveThread(socket);
Thread rt = new Thread(receiveThread);
rt.start();
// 发送的socket,用连接用户的socket
sendThread = new SendThread();
Thread st = new Thread(sendThread);
st.start();
}
/**
* 发送线程
*
* @author Administrator
*
*/
class SendThread implements Runnable {
private void sendMessage() {
try {
Message m = message.getMessage();
Socket socket = new Socket(m.getToUrl(), m
.getToPort());
System.out.println("Server-Sending:" + m);
ObjectOutputStream output = new ObjectOutputStream(socket
.getOutputStream());
output.writeObject(m);// 发送对象
output.flush();
output.close();
} catch (IOException ex) {
System.out.println("发送线程没有连接上!发送失败!");
//这里表示要发送的目标客户没有连接上。因此如果没有连接上可以将这条消息保存下来等客户连接上的时候再发送过去。相当于QQ的离线消息
}
}
public void run() {
sendMessage();
}
}
/**
* 接收线程
*
* @author Administrator
*
*/
class ReceiveThread implements Runnable {
private Socket socket;
public ReceiveThread(Socket socket) {
this.socket = socket;
}
/**
* 接收到对象然后赋给message,再调用message上面阻塞的发送线程
*/
private void setMessage() {
try {
ObjectInputStream input = new ObjectInputStream(socket
.getInputStream());
Object messObject = input.readObject();
System.out.println("Server-Receiving:" + messObject);
if (messObject instanceof Message) {
Message m = (Message) messObject;
message.setMessage(m);
}
} catch (IOException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException ex) {
System.out.println("传输出现问题!");
}
}
public void run() {
if (socket != null) {
setMessage();
}
}
}
}
public static void main(String[] args) {
Server s = new Server();
Thread st = new Thread(s);
st.start();
}
}
2.Client.java:客户端,通过Server中转来对其它客户端发送消息,并接受其它客户端的消息
package com.icarusliu.learn.chart.test3;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Client {
//这个客户端的名称
private String name;
//服务器信息
private final String serverUrl = "localhost";
private final int serverPort = 9001;
//客户端信息,暂只有一个客户端,后面可以改成多个这些信息应该来自于客户端
private String clientUrl = "localhost";
private int clientPort = 9002;
private int client2Port = 9003;
public Client(String name,String clientUrl,int clientPort,int client2Port){
this.name = name;
this.clientUrl = clientUrl;
this.clientPort = clientPort;
this.client2Port = client2Port;
}
public void start(){
try{
SendThread st = new SendThread();
Thread t = new Thread(st);
t.start();
ReceiveThread rt = new ReceiveThread();
Thread rtt = new Thread(rt);
rtt.start();
}catch(Exception ex){
ex.printStackTrace();
}
}
/**
* 接收线程
* @author Administrator
*
*/
class ReceiveThread implements Runnable{
public void run(){
try{
ServerSocket ss = new ServerSocket(clientPort);
while(true){
Socket s = ss.accept();
ObjectInputStream input = new ObjectInputStream(s.getInputStream());
System.out.println(name + "-Receiving111:" + input.readObject());
input.close();
}
}catch(IOException ex){
System.out.println("接收线程初始化失败!");
}catch(ClassNotFoundException ex){
System.out.println("没有找到对象!");
}
}
}
/**
* 发送线程
* @author Administrator
*
*/
class SendThread implements Runnable{
public void sendMessage(String message){
try{
System.out.println(name + "Sending:" + message);
Socket socket = new Socket(serverUrl,serverPort);
Message m = new Message(message,clientUrl,client2Port,clientUrl,clientPort);
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
output.writeObject(m);
output.flush();
output.close();
}catch(IOException ex){
ex.printStackTrace();
}
}
public void run(){
int i=3;
while(i-->0){
sendMessage("message from " + name + i);
try{
Thread.sleep(1000);
}catch(Exception ex){
ex.printStackTrace();
}
}
}
}
public static void main(String[] args){
Client client = new Client("client1","localhost",9002,9003);
client.start();
Client client2 = new Client("client2","localhost",9003,9002);
client2.start();
}
}
3.Message.java:传递的消息对象
package com.icarusliu.learn.chart.test3;
import java.io.Serializable;
/**
* 消息
*
* @author Administrator
*
*/
class Message implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String value;
// 消息目的地
private String toUrl;
private int toPort;
// 消息来源
private String fromUrl;
private int fromPort;
public Message() {
}
public Message(String value, String toUrl, int toPort, String fromUrl,
int fromPort) {
this.value = value;
this.toUrl = toUrl;
this.toPort = toPort;
this.fromPort = fromPort;
this.fromUrl = fromUrl;
}
/**
* 设置消息 唤醒等待线程
*
* @param message
*/
public synchronized void setMessage(Message message) {
this.value = message.getValue();
this.toUrl = message.getToUrl();
this.toPort = message.getToPort();
this.fromPort = message.getFromPort();
this.fromUrl = message.getFromUrl();
notifyAll();
}
/**
* 取得消息,如果消息为空,那么等待
*
* @return
*/
public synchronized Message getMessage() {
if (value == null || value.equals("")) {
try {
wait();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
Message message = new Message(value, toUrl, toPort, fromUrl, fromPort);
this.setNull();
return message;
}
public String getToUrl() {
return this.toUrl;
}
public int getToPort() {
return this.toPort;
}
public String getFromUrl() {
return this.fromUrl;
}
public int getFromPort() {
return this.fromPort;
}
public String getValue() {
return this.value;
}
public void setNull() {
this.value = null;
}
public String toString() {
return "Message:(" + this.getValue() + "-" + this.getFromUrl()
+ this.getFromPort() + "-" + this.getToUrl() + this.getToPort()
+ ")";
}
}
4.执行结果:
Server端:
Server-Server started!
Server-User:127.0.0.1(1179) connected!
Server-User:127.0.0.1(1178) connected!
Server-Receiving:Message:(message from client12-localhost9002-localhost9003)
Server-Receiving:Message:(message from client22-localhost9003-localhost9002)
Server-Sending:Message:(message from client22-localhost9003-localhost9002)
Server-Sending:Message:(message from client12-localhost9002-localhost9003)
Server-User:127.0.0.1(1182) connected!
Server-User:127.0.0.1(1183) connected!
Server-Receiving:Message:(message from client21-localhost9003-localhost9002)
Server-Sending:Message:(message from client21-localhost9003-localhost9002)
Server-Receiving:Message:(message from client11-localhost9002-localhost9003)
Server-Sending:Message:(message from client11-localhost9002-localhost9003)
Server-User:127.0.0.1(1186) connected!
Server-User:127.0.0.1(1187) connected!
Server-Receiving:Message:(message from client20-localhost9003-localhost9002)
Server-Receiving:Message:(message from client10-localhost9002-localhost9003)
Server-Sending:Message:(message from client20-localhost9003-localhost9002)
Server-Sending:Message:(message from client10-localhost9002-localhost9003)
Server-User:127.0.0.1(1191) connected!
Server-User:127.0.0.1(1190) connected!
Server-Receiving:Message:(message from client22-localhost9003-localhost9002)
Server-Receiving:Message:(message from client12-localhost9002-localhost9003)
Server-Sending:Message:(message from client22-localhost9003-localhost9002)
Server-Sending:Message:(message from client12-localhost9002-localhost9003)
Server-User:127.0.0.1(1195) connected!
Server-User:127.0.0.1(1194) connected!
Server-Receiving:Message:(message from client11-localhost9002-localhost9003)
Server-Sending:Message:(message from client11-localhost9002-localhost9003)
Server-Receiving:Message:(message from client21-localhost9003-localhost9002)
Server-Sending:Message:(message from client21-localhost9003-localhost9002)
Server-User:127.0.0.1(1198) connected!
Server-User:127.0.0.1(1199) connected!
Server-Receiving:Message:(message from client20-localhost9003-localhost9002)
Server-Sending:Message:(message from client20-localhost9003-localhost9002)
Server-Receiving:Message:(message from client10-localhost9002-localhost9003)
Server-Sending:Message:(message from client10-localhost9002-localhost9003)
Client端:
client1Sending:message from client12
client2Sending:message from client22
client1-Receiving111:Message:(message from client22-localhost9003-localhost9002)
client2-Receiving111:Message:(message from client12-localhost9002-localhost9003)
client1Sending:message from client11
client2Sending:message from client21
client2-Receiving111:Message:(message from client11-localhost9002-localhost9003)
client1-Receiving111:Message:(message from client21-localhost9003-localhost9002)
client2Sending:message from client20
client1Sending:message from client10
client1-Receiving111:Message:(message from client20-localhost9003-localhost9002)
client2-Receiving111:Message:(message from client10-localhost9002-localhost9003)