感谢大家对IT十八掌大数据的支持,今天的作业如下:


按照老师讲的,自己练习项目







--------------------------------------------------------------------------------------------------------

项目源码:


package com.it18zhang.client;


import java.net.Socket;


/**

 * 通信类,单例类

 */

public class Comm {

private String ip = "192.168.12.2";

private int port = 1234 ;

private static Comm instance ;

private Socket sock ;

private ReceiverThread receiver ;

private SenderThread sender ;

public Socket getSock() {

return sock;

}

public void setSock(Socket sock) {

this.sock = sock;

}

/**

* 返回单例对象

*/

public static Comm getInstance(MyWindow window){

if(instance == null){

instance = new Comm(window);

}

return instance ;

}

private Comm(MyWindow window) {

try {

sock = new Socket(ip, port);

//启动后台接收线程

receiver = new ReceiverThread(sock, window);

receiver.start();

//启动后台发送线程

sender = new SenderThread(sock);

sender.start();

}

catch (Exception e) {

}

}

public String getIp() {

return ip;

}

public void setIp(String ip) {

this.ip = ip;

}

public int getPort() {

return port;

}

public void setPort(int port) {

this.port = port;

}


/**

* 发送消息

*/

public void sendText(String txt) {

sender.setTxt(txt);

}

}


package com.it18zhang.client;


import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

import java.awt.event.WindowAdapter;

import java.awt.event.WindowEvent;

import java.util.ArrayList;

import java.util.HashSet;

import java.util.List;

import java.util.Set;


import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JList;

import javax.swing.JScrollPane;

import javax.swing.JTable;

import javax.swing.JTextArea;

import javax.swing.table.AbstractTableModel;

import javax.swing.table.TableModel;


/**

 * 窗体

 */

public class MyWindow extends JFrame {

private static final long serialVersionUID = -6944831795769317874L;

// 历史记录

private JTextArea taHistory;

//滚动面板

private JScrollPane spHistory ;

// 内容

private JTextArea taContent;

// 发送按钮

private JButton btnSend;

// 联系人列表

private JList listContacts;


private JTable table;


public MyWindow() {

ini();

}


// 初始化

private void ini() {

//

this.setSize(600, 400);

this.setLocation(200, 200);


// 绝对布局

this.setLayout(null);


//联系人表格

table = new JTable();

table.setBounds(500, 0, 100, 400);

this.add(table);

//聊天记录区

taHistory = new JTextArea();

taHistory.setEditable(false);

taHistory.setBounds(0, 0, 480, 300);

//

spHistory = new JScrollPane(taHistory);

spHistory.setBounds(0, 0, 480, 300);

this.add(spHistory);

//输入区

taContent = new JTextArea();

taContent.setBounds(0, 310,450, 90);

this.add(taContent);

//发送按钮

btnSend = new JButton("发送");

btnSend.setBounds(460,350 , 50, 50);

btnSend.addMouseListener(new MouseAdapter() {

public void mouseClicked(MouseEvent e) {

//发送消息

String txt = taContent.getText();

Comm comm = Comm.getInstance(MyWindow.this);

comm.sendText(txt);

//清空输入区

taContent.setText("");

}

});

this.add(btnSend);

this.setVisible(true);

// 事件

this.addWindowListener(new WindowAdapter() {

public void windowClosing(WindowEvent e) {

System.exit(-1);

}

});

}


/**

* 刷新联系人

*/

public void refreshFriendsUI(final List<String> friends) {

//去重

Set<String> set = new HashSet<String>(friends);

//

final List<String> newclients = new ArrayList<String>(set);

//

TableModel dataModel = new AbstractTableModel() {

public int getColumnCount() {

return 1;

}

public int getRowCount() {

return newclients.size();

}

public Object getValueAt(int row, int col) {

return newclients.get(row);

}

};

table.setModel(dataModel);

}


/**

* 更新聊天记录

*/

public void updateHistory(String addr, String line) {

//原文

String old = taHistory.getText();

StringBuilder builder = new StringBuilder();

builder.append(old);

builder.append("\r\n");

builder.append(addr);

builder.append("\r\n");

builder.append(line);

builder.append("\r\n");

//更新聊天区域

taHistory.setText(builder.toString());

}


/**

* 追加内容到聊天区域

*/

public void appendCont2History(String cont) {

String old = taHistory.getText() ;

StringBuilder builder = new StringBuilder();

builder.append(old);

builder.append("\r\n");

builder.append(cont);

String newCont = builder.toString();

taHistory.setText(newCont);

}

}




package com.it18zhang.client;


public class QQ {


public static void main(String[] args) {

MyWindow window = new MyWindow();

Comm comm = Comm.getInstance(window);

}


}


package com.it18zhang.client;


import java.io.InputStream;

import java.net.Socket;

import java.util.List;


import com.it18zhang.common.Message;

import com.it18zhang.common.MessageFactory;

import com.it18zhang.server.LatestFriendsServerMessage;

import com.it18zhang.server.TalkServerMessage;

import com.it18zhang.util.SocketUtil;


/**

 * 接收者线程

 */

public class ReceiverThread extends Thread {

//客户端UI

private MyWindow window ;

//sock

private Socket sock ;

//输入流,读取服务器回传的信息

private InputStream is ;

public ReceiverThread(Socket sock,MyWindow window){

try {

this.sock = sock ;

this.window = window ;

is = sock.getInputStream() ;

}

catch (Exception e) {

e.printStackTrace();

}

}

public void run() {

try {

//读取消息类型

//读取文件长度

//读取消息内容

while(true){

processMessage();

}

}

catch (Exception e) {

}

}

/**

* 处理消息

*/

private void processMessage() {

Message msg = MessageFactory.parsePack(is);

int type = msg.getType();

switch(type){

//刷新列表

case Message.MESSAGE_TYPE_SERVER_REFRESHFRIENDS:

List<String> list = (List<String>)((LatestFriendsServerMessage)msg).getData();

window.refreshFriendsUI(list);

break ;

//服务器对话

case Message.MESSAGE_TYPE_SERVER_TALK:

String str = (String) ((TalkServerMessage)msg).getData();

window.appendCont2History(str);

break ;

}

}

}



package com.it18zhang.client;


import com.it18zhang.common.Message;


/**

 * 客户端请求刷新好友列表消息 

 */

public class RequestFriendsClientMessage extends Message {

public RequestFriendsClientMessage() {

this.setType(Message.MESSAGE_TYPE_CLIENT_REQUESTFRIENDS);

}

/**

* 重写该方法,该消息没有消息长度和消息内容。

*/

public byte[] genMessagePack() {

byte[] bytes = new byte[1];

bytes[0] = (byte)this.getType();

return bytes ;

}

/**

* 无需实现

*/

public Object getData() {

return null;

}

}




package com.it18zhang.client;


import java.io.IOException;

import java.io.OutputStream;

import java.net.Socket;


import com.it18zhang.util.SocketUtil;


/**

 * 发送者线程

 */

public class SenderThread extends Thread {

private String txt ;

private OutputStream os ;

public SenderThread(Socket sock){

try {

this.os = sock.getOutputStream() ;

}

catch (IOException e) {

e.printStackTrace();

}

}

public String getTxt() {

return txt;

}



public void setTxt(String txt) {

this.txt = txt;

}


public void run() {

while(true){

if(txt != null){

//发送

SocketUtil.writeMessage(os, txt);

txt = null ;

}

}

}

}




package com.it18zhang.client;


import com.it18zhang.common.Message;

/**

 * 客户端输入的话语消息

 */

public class TalkClientMessage extends Message {

public TalkClientMessage(String text) {

//处理消息

this.setType(Message.MESSAGE_TYPE_CLIENT_TALK) ;

byte[] bytes = text.getBytes() ;

this.setContent(bytes);

}


/**

* 无需实现

*/

public Object getData() {

return null;

}

}


package com.it18zhang.common;


import com.it18zhang.util.SocketUtil;

/**

 * 消息

 */

public abstract class Message {

//客户端发送talk

public static final int MESSAGE_TYPE_CLIENT_TALK = 0 ;

//客户端请求好友列表(手动刷新)

public static final int MESSAGE_TYPE_CLIENT_REQUESTFRIENDS = 1 ;

//服务端推送刷新好友列表

public static final int MESSAGE_TYPE_SERVER_REFRESHFRIENDS = 2 ;

//推送某个客户端的说的话

public static final int MESSAGE_TYPE_SERVER_TALK = 3 ;

//消息类型

private int type ;

//消息长度

private int length ;

//消息内容

private byte[] content ;

//原生报文

private byte[] pack ;

public Message(){

}

public int getType() {

return type;

}

public void setType(int type) {

this.type = type;

}

public int getLength() {

return length;

}

public void setLength(int length) {

this.length = length;

}

public byte[] getContent() {

return content;

}

public void setContent(byte[] content) {

this.content = content;

this.length = content.length ;

}

public byte[] getPack() {

return pack;

}

public void setPack(byte[] pack) {

this.pack = pack;

}

/**

* 生成整个报文,含有头信息 + 消息本身

*/

public byte[] genMessagePack(){

pack = new byte[1 + 4 + length];

//类型

pack[0] = (byte)type ;

//数组复制

byte[] lenArr = SocketUtil.int2ByteArr(length);

System.arraycopy(lenArr, 0, pack, 1, 4);

//内容复制

System.arraycopy(content, 0, pack, 5, length);

return pack ;

}

public abstract Object getData() ;

}



package com.it18zhang.common;


import java.io.InputStream;


import com.it18zhang.server.LatestFriendsServerMessage;

import com.it18zhang.server.MessageServer;

import com.it18zhang.server.TalkServerMessage;

import com.it18zhang.util.SocketUtil;


/**

 * 消息工厂 

 */

public class MessageFactory {

/**

* 转换报文,返回服务器端的消息对象,该方法只给服务器使用

*/

public static Message tranformPack(InputStream is){

Message msg = null ;

try {

//消息类型

int type = is.read();

int length = 0 ;

byte[] cont = null ;

switch(type){

//客户端talk消息

case Message.MESSAGE_TYPE_CLIENT_TALK:

//消息长度

length = SocketUtil.readMsglength(is);

cont = SocketUtil.readMessage(is, length);

//转换成服务器talk

msg = new TalkServerMessage(length,cont);

break ;

//客户端刷新好友

case Message.MESSAGE_TYPE_CLIENT_REQUESTFRIENDS:

msg = new LatestFriendsServerMessage(MessageServer.friends);

break ;

}

//返回消息

return msg ;

}

catch (Exception e) {

}

return null ;

}

/**

* 解析报文,提取消息内容,只给客户端使用

*/

public static Message parsePack(InputStream is){

Message msg = null;

try {

//消息类型

int type = is.read();

int length = 0 ;

byte[] cont = null ;

//消息长度

length = SocketUtil.readMsglength(is);

cont = SocketUtil.readMessage(is, length);

switch(type){

//客户端talk消息

case Message.MESSAGE_TYPE_SERVER_TALK:

msg = new TalkServerMessage(length, cont);

break ;

//客户端刷新好友

case Message.MESSAGE_TYPE_SERVER_REFRESHFRIENDS:

msg = new LatestFriendsServerMessage(cont);

break ;

}

//返回消息

return msg ;

}

catch (Exception e) {

}

return null ;

}

}




package com.it18zhang.server;


import java.io.ByteArrayOutputStream;

import java.io.ObjectOutputStream;

import java.util.List;


import com.it18zhang.common.Message;

import com.it18zhang.util.SocketUtil;


/**

 * 服务器端消息,最新的好友列表

 */

public class LatestFriendsServerMessage extends Message {

public LatestFriendsServerMessage(List<String> list){

this.setType(MESSAGE_TYPE_SERVER_REFRESHFRIENDS);

this.setContent(serialFriends(list));

}

public LatestFriendsServerMessage(byte[] content){

this.setType(MESSAGE_TYPE_SERVER_REFRESHFRIENDS);

this.setContent(content);

}

/**

* 串行好友列表

*/

private byte[] serialFriends(List<String> list){

try {

ByteArrayOutputStream baos = new ByteArrayOutputStream();

ObjectOutputStream oos = new ObjectOutputStream(baos);

oos.writeObject(list);

oos.close();

baos.close();

return baos.toByteArray();

}

catch (Exception e) {

e.printStackTrace();

}

return null ;

}


/**

* 取得消息中的数据部分,反串行化。

*/

public Object getData() {

return SocketUtil.deserializeFriends(getContent());

}

}


package com.it18zhang.server;


import java.io.IOException;

import java.net.Socket;


import com.it18zhang.common.Message;

import com.it18zhang.util.SocketUtil;


/**

 * 服务器消息推送器

 */

public class MessagePusher {

/**

* 推送消息 

*/

public static void push(final Message msg){

//遍历所有socket

for(final Socket s : MessageServer.allSockets){

new Thread(){

public void run() {

try {

SocketUtil.writeMessage(s.getOutputStream(), msg);

}

catch (IOException e) {

e.printStackTrace();

}

}

}.start();

}

}

}



package com.it18zhang.server;


import java.net.InetAddress;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.ArrayList;

import java.util.List;


import com.it18zhang.util.SocketUtil;


/**

 * 

 */

public class MessageServer {

//客户端集合

public static List<String> friends  = new ArrayList<String>();

//存放所有socket

public static List<Socket> allSockets = new ArrayList<Socket>();

//启动

public void start(int port){

try {

ServerSocket ss = new ServerSocket(port);

System.out.println("服务器启动了!!");

while(true){

Socket sock = ss.accept();

//添加好友

friends.add(SocketUtil.getAddr(sock));

//维护socket集合

allSockets.add(sock);

MessagePusher.push(new LatestFriendsServerMessage(friends));

//分配线程,单独处理

new ServerReceiverThread(sock).start();

}

}

catch (Exception e) {

}

}

}



package com.it18zhang.server;


import java.io.IOException;

import java.io.InputStream;

import java.net.Socket;


import com.it18zhang.common.Message;

import com.it18zhang.common.MessageFactory;

import com.it18zhang.util.SocketUtil;


import sun.awt.windows.ThemeReader;


/**

 * 服务器接收线程.

 */

public class ServerReceiverThread extends Thread {


private Socket sock ;

private InputStream is ;

public ServerReceiverThread(Socket sock) {

try {

this.sock = sock ;

this.is = sock.getInputStream() ;

}

catch (Exception e) {

e.printStackTrace();

}

}


public void run() {

while(true){

//

try {

//转成服务器消息

Message msg = MessageFactory.tranformPack(is);

//

int type = msg.getType();

switch(type){

case Message.MESSAGE_TYPE_SERVER_TALK : 

MessagePusher.push(msg);

break ;

case Message.MESSAGE_TYPE_SERVER_REFRESHFRIENDS:

MessagePusher.push(msg);

break ;

}

}

catch (Exception e) {

e.printStackTrace();

}

}

}

}





package com.it18zhang.server;


public class StartServer {


public static void main(String[] args) {

//消息服务器

MessageServer server = new MessageServer();

//启动消息服务器

server.start(1234);

}


}


package com.it18zhang.server;


import com.it18zhang.common.Message;


/**

 * 服务器端推送给客户端的talk消息

 */

public class TalkServerMessage extends Message {

public TalkServerMessage(String text){

//处理消息

this.setType(Message.MESSAGE_TYPE_SERVER_TALK) ;

byte[] bytes = text.getBytes() ;

this.setContent(bytes);

}

/**

* 直接通过原生报文构造消息对象

*/

public TalkServerMessage(byte[] pack){

this.setPack(pack);

pack[0] = Message.MESSAGE_TYPE_SERVER_TALK ;

}

/**

* 直接通过原生报文构造消息对象

*/

public TalkServerMessage(int length,byte[] content){

this.setType(Message.MESSAGE_TYPE_SERVER_TALK) ;

this.setContent(content);

}

public byte[] genMessagePack() {

if(getPack() != null){

return getPack();

}

else{

return super.genMessagePack();

}

}


public Object getData() {

return new String(getContent());

}

}




package com.it18zhang.util;


import java.io.ByteArrayInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.ObjectInputStream;

import java.io.OutputStream;

import java.io.UnsupportedEncodingException;

import java.net.Socket;

import java.util.List;


import com.it18zhang.common.Message;


/**

 * 工具类

 */

public class SocketUtil {

/**

* 返回地址串

*/

public static String getAddr(Socket sock){

String ip = sock.getInetAddress().getHostName() ;

String ip0 = ip.substring(ip.lastIndexOf(".") + 1);

return ip0 + ":" + sock.getPort() ;

}

/**

* 从输入流is的当前读取byte,处理成消息类型.

* 0-好友列表  1-文本内容

*/

public static int readMsgType(InputStream is){

try {

return is.read() ;

}

catch (IOException e) {

e.printStackTrace();

}

return -1 ;

}

/**

* 读取消息的长度

*/

public static int readMsglength(InputStream is){

try {

byte[] buf = new byte[4];

is.read(buf);

//最高位

int s3 =  buf[0] << 24 ;

//次高位

int s2 =  (buf[1] & 0xFF) << 16  ;

//次低位

int s1 =  (buf[2] & 0xFF) << 8 ;

//最低位

int s0 =  buf[3] & 0xFF ;

return s3 | s2 | s1 | s0 ;

}

catch (Exception e) {

e.printStackTrace();

}

return -1 ;

}

/**

* 读取指定消息长度的内容

*/

public static byte[] readMessage(InputStream is,int len){

try {

byte[] bytes = new byte[len];

is.read(bytes);

return bytes ;

}

catch (IOException e) {

e.printStackTrace();

}

return null ;

}

/**

* 反序列化字节数组成好友列表

*/

public static List<String> deserializeFriends(byte[] bytes){

try {

ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));

List<String> list= (List<String>)ois.readObject();

ois.close();

return list ;

}

catch (Exception e) {

e.printStackTrace();

}

return null ;

}

/**

* 读取字符串

*/

public static String readString(byte[] bytes){

return new String(bytes);

}

/**

* 使用指定的字符集读取字符串

*/

public static String readString(byte[] bytes,String charset){

try {

return new String(bytes,charset);

}

catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

return null ;

}

/**

* 发送消息到os中

*/

public static void writeMessage(OutputStream os , String txt){

try {

byte[] bytes = txt.getBytes();

//先写入字节数组的长度

os.write(int2ByteArr(bytes.length));

//再写入字节

os.write(bytes);

}

catch (Exception e) {

e.printStackTrace();

}

}

/**

* 发送Message的原始报文到os中

*/

public static void writeMessage(OutputStream os , Message msg){

try {

os.write(msg.genMessagePack());

os.flush();

}

catch (Exception e) {

e.printStackTrace();

}

}

/**

* 整型转换成字节数组

*/

public static byte[] int2ByteArr(int i){

byte[] bytes = new byte[4] ;

bytes[0] = (byte)(i >> 24) ;

bytes[1] = (byte)(i >> 16) ;

bytes[2] = (byte)(i >> 8) ;

bytes[3] = (byte)(i >> 0) ;

return bytes ;

}

}