上一篇实现了服务端,本篇主要展示 客户端代码的设计
客户端的代码比较复杂一点,由于P2P中,客户端要二者兼顾。
注意:目前本实例中只实现了消息的传输,但大致框架已定,后面的文件传输很简单了。
废话不多,首先上效果:(由于时间比较紧,只是初步实现了,欢迎大家二次创作,优化加强!!)
详细代码如下:
JJTalkClient.java
它是客户端主程序
package InternetCode.Socket.JJTalk;
import InternetCode.Socket.JJTalk.ClientUtil.ClientAbleUtil;
import InternetCode.Socket.JJTalk.ClientUtil.ClientThread;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import static InternetCode.Socket.JJTalk.ClientUtil.ClientAbleUtil.makeActiveClientInfo;
public class JJTalkClient {
// 创建流对象
private ObjectOutputStream out = null;
// 创建流对象
private ObjectInputStream in = null;
//声明服务器Socket
private ServerSocket serverSocket;
/**
* 新建服务器对象并等待连接
*/
public void getConnect(){
try { // 捕捉异常
Socket socket;
System.out.println("开始连接服务器");
socket = new Socket("127.0.0.1", 2006); // 实例化Socket对象
//客户端信息注册
ClientAbleUtil ableUtil=new ClientAbleUtil();
ableUtil.sendObject(makeActiveClientInfo(),socket);
new ClientThread(socket,ableUtil,"N","成功连接到服务器").start();
} catch (Exception e) {
e.printStackTrace(); // 输出异常信息
}
}
/**
* 新建服务器对象并等待连接
*/
public void getServer() {
try {
serverSocket = new ServerSocket(1998);
while (true) {
Socket socket;
// 监听是否有客户端连接
System.out.println("等待连接!!");
socket = serverSocket.accept();
System.out.println("连接成功!");
ClientAbleUtil ableUtil=new ClientAbleUtil();
// 创建并启动连接线程对象
ClientThread clientThread=new ClientThread(socket,ableUtil,"Y",socket.getInetAddress().getHostName()+"向您发起会话");
clientThread.start();
}
} catch (Exception e) {
e.printStackTrace(); // 输出异常信息
}
}
public static void main(String[] args) {
JJTalkClient client=new JJTalkClient();
//连接服务器线程
new Thread(new Runnable() {
@Override
public void run() {
client.getConnect();
}
}).start();
//监听连接线程
new Thread(new Runnable() {
@Override
public void run() {
client.getServer();
}
}).start();
}
}
ClientThread.java
它主要负责图形化界面的展示和事件处理
package InternetCode.Socket.JJTalk.ClientUtil;
import InternetCode.Socket.JJTalk.pojo.ClientInfo;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.Socket;
public class ClientThread extends Thread{
//连接服务器的套接字
Socket socket;
ClientAbleUtil ableUtil;
//连接客户端的套接字
Socket clientSocket;
ClientAbleUtil ableUtil1;
//是否客户端标志
String clientFlat;
String text;
// 创建JTextArea对象
public JTextArea outInfo = new JTextArea();
public ClientThread(Socket socket,ClientAbleUtil ableUtil,String clientFlat,String text) throws IOException {
this.socket = socket;
this.ableUtil=ableUtil;
this.clientFlat=clientFlat;
this.text=text;
}
public void run() {
try {
new Thread(new Runnable() {
@Override
public void run() {
//运行图像化界面
Frame frame=new Frame(text);
frame.setVisible(true);
}
}).start();
//监听发送方发送的消息
if(clientFlat.equals("Y")){
new Thread(new Runnable(){
@Override
public void run() {
while (true){
String line=ableUtil.getInfo(socket);
if(line!=null){
outInfo.append("\n");
outInfo.append(socket.getInetAddress().getHostName()+"发送消息:"+line);
}
}
}
}).start();
}
} catch (Exception e) {
System.out.println(socket + "已经退出。\n");
}
}
class Frame extends JFrame{
//连接客户端文本框
private JTextField connectJText;
//发送信息文本狂
private JTextField sendInfoJText;
public Frame(String text) {
super();
setTitle("客户端程序");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(500, 100, 800, 700);
final JScrollPane scrollPane = new JScrollPane();
getContentPane().setLayout(new GridLayout(1,2));
getContentPane().add(scrollPane);
scrollPane.setViewportView(outInfo);
getContentPane().add(getMainPanel());
outInfo.append(text);
}
/**得到按钮对象
* @return 按钮对象
*/
protected JButton getButton(String text) {
JButton jButton=new JButton();
jButton = new JButton();
jButton.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
if(text.equals("连接")){
ClientInfo clientInfo=new ClientInfo();
clientInfo.setClientId(connectJText.getText());
clientInfo.setQuery("Y");
System.out.println("开始向服务器发送查询信息");
ableUtil.sendObject(clientInfo,socket);
//等待接收服务器发送来的客户信息
try{
clientInfo=ableUtil.getClientInfoFromServer(socket);
}catch (Exception e3){
e3.printStackTrace();
}
if(clientInfo.isActive().equals("Y")){
//连接通信对方
try {
outInfo.append("开始连接客户:"+clientInfo.getClientId());
// 实例化Socket对象
clientSocket = new Socket(clientInfo.getIp(),Integer.parseInt(clientInfo.getPort()));
ableUtil1=new ClientAbleUtil();
outInfo.append("\n");
outInfo.append("连接成功!!可以开始通信了");
//监听请求方发送的消息
new Thread(new Runnable() {
@Override
public void run() {
while (true){
String line=ableUtil1.getInfo(clientSocket);
if(line!=null){
outInfo.append("\n");
outInfo.append(clientSocket.getInetAddress().getHostName()+"发送消息:"+line);
}
}
}
}).start();
} catch (Exception ex) {
ex.printStackTrace(); // 输出异常信息
}
}else if(clientInfo.isActive().equals("N")){
//对方不在线,输出提示信息
outInfo.append("对方不在线,请稍后在试!!");
}else{
outInfo.append("不存在此用户!!!请检查");
}
}
//发送消息给对方
if(text.equals("发送")){
if(clientFlat.equals("N")){
ableUtil1.sendInfo(sendInfoJText.getText(),clientSocket);
}else{
ableUtil.sendInfo(sendInfoJText.getText(),socket);
}
}
if(text.equals("选择文件")){
}
if(text.equals("发送文件")){
}
}
});
jButton.setText(text);
return jButton;
}
/**
* 得到画板对象
* @return 返回画板
*/
protected JPanel getMainPanel() {
JPanel panel;
panel = new JPanel();
panel.setLayout(new GridLayout(4,1));
panel.add(getConnectPanel());
panel.add(getSendDataPanel());
panel.add(getSendDataPathPanel());
panel.add(getSendInfoPanel());
return panel;
}
/**
* 得到连接客户端画板对象
* @return 返回画板
*/
protected JPanel getConnectPanel() {
JPanel panel;
connectJText=getJTextFiled(100,25);
panel = new JPanel();
panel.add(getLabel("对方客户端名称:"));
panel.add(connectJText);
panel.add(getButton("连接"));
return panel;
}
/**
* 得到发送信息的画板
* @return
*/
protected JPanel getSendInfoPanel() {
JPanel panel;
sendInfoJText=getJTextFiled(200,100);
panel = new JPanel();
panel.add(getLabel("请输入要发送的信息:"));
panel.add(sendInfoJText);
panel.add(getButton("发送"));
return panel;
}
/**
* 得到发送数据文件的画板
* @return 发送数据的画板
*/
protected JPanel getSendDataPanel() {
JPanel panel;
panel = new JPanel();
panel.add(getLabel("选择要发送的文件:"));
panel.add(getButton("选择文件"));
return panel;
}
/**
* 得到发送数据文件的画板
* @return 发送数据的画板
*/
protected JPanel getSendDataPathPanel() {
JPanel panel;
panel = new JPanel();
panel.add(getLabel("文件路径:"));
panel.add(getButton("发送文件"));
return panel;
}
/**文本标签
* @return
*/
protected JLabel getLabel(String text) {
JLabel jLabel=new JLabel();
jLabel.setText(text);
return jLabel;
}
/**获得输入框
* @param width
* @param height
* @return 输入框对象
*/
protected JTextField getJTextFiled(int width,int height) {
JTextField jTextField;
jTextField = new JTextField();
jTextField.setPreferredSize(new Dimension(width, height));
return jTextField;
}
}
}
ClientAbleUtil.java
这个类主要将Socket通信能力集合起来方便使用
package InternetCode.Socket.JJTalk.ClientUtil;
import InternetCode.Socket.JJTalk.pojo.ClientInfo;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class ClientAbleUtil {
private ObjectOutputStream objectOut;
private ObjectInputStream objectIn;
private PrintWriter infoOut;
private BufferedReader infoIn;
private DataOutputStream DataOut;
private DataInputStream DataIn;
/**
* 生成活跃信息
* @return
* @throws UnknownHostException
*/
public static ClientInfo makeActiveClientInfo() throws UnknownHostException {
InetAddress inetAdder = InetAddress.getLocalHost();
ClientInfo clientInfo=new ClientInfo();
clientInfo.setClientId(String.valueOf(System.currentTimeMillis()));
clientInfo.setActive("Y");
clientInfo.setIp(inetAdder.getHostAddress());
clientInfo.setPort("1998");
clientInfo.setQuery("N");
return clientInfo;
}
/**
* 发送信息
* @param info
* @param socket
*/
public void sendInfo(String info, Socket socket){
try{
if(infoOut==null){
infoOut=new PrintWriter(socket.getOutputStream(),true);
}
infoOut.println(info);
System.out.println("发送消息完成: "+info+"发送到:"+socket.getInetAddress().getHostAddress()+":"+socket.getPort());
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 发送对象
* @param obj 要发送的对象
* @param socket 连接套接字
*/
public void sendObject(Object obj, Socket socket){
try {
if(objectOut==null){
objectOut=new ObjectOutputStream(socket.getOutputStream());
}
objectOut.writeObject(obj);
System.out.println("发送对象完成");
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 发送数据文件
* @param file 要发送的文件对象
* @param socket 连接套接字
*/
public void sendData(File file, Socket socket){
long lengths;
try {
if(socket!=null){
if(DataOut==null){
DataOut=new DataOutputStream(socket.getOutputStream());
}
DataInputStream inStream = null;// 定义数据输入流对象
FileInputStream inFile;
if (file != null) {
lengths = file.length();
inFile=new FileInputStream(file);
inStream = new DataInputStream(inFile);
} else {
System.out.println("没有选择文件。");
return;
}
DataOut.writeLong(lengths);
DataOut.writeUTF(file.getName());
byte[] bt = new byte[(int) lengths];
int len = -1;
while ((len = inStream.read(bt)) != -1) {
DataOut.write(bt);// 将字节数组写入输出流
}
inStream.close();
inFile.close();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
/**
* 监听接收服务端返回的对象信息
* @param socket
* @return
*/
public ClientInfo getClientInfoFromServer(Socket socket) throws IOException {
try {
if(socket!=null){
if(objectIn==null){
objectIn=new ObjectInputStream(socket.getInputStream());
}
while (true){
ClientInfo clientInfo=(ClientInfo) objectIn.readObject();
if(clientInfo!=null){
System.out.println("接收对象完成");
return clientInfo;
}
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
objectIn.close();
}
return null;
}
/**
* 监听其他节点传过来的信息
* @param socket
* @return
*/
public String getInfo(Socket socket){
String info=null;
try {
if(socket!=null){
if(infoIn==null){
infoIn=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
while (true){
info=infoIn.readLine();
if(info!=null){
System.out.println("接收消息完成:"+info);
return info;
}
}
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
/**
* 等待客户端发送数据并接收
*/
public boolean getData(Socket socket) {
try {
if(socket!=null){
if(DataIn==null){
DataIn=new DataInputStream(socket.getInputStream());
}
while (true){
// 读取数据文件大小
long lengths = DataIn.readLong();
if(lengths>0){
String fileName=DataIn.readUTF();
// 创建字节数组
byte[] bt = new byte[(int) lengths];
for (int i = 0; i < bt.length; i++) {
bt[i] = DataIn.readByte();// 读取字节信息并存储到字节数组
}
File img=new File(String.valueOf(Math.random())+fileName);
OutputStream out=new DataOutputStream(new FileOutputStream(img));
out.write(bt);
System.out.println("文件接收成功!!");
return true;
}
}
}
} catch(Exception e){
e.printStackTrace();
} finally {
try {
if (DataIn != null) {
DataIn.close();// 关闭流
}
if (socket != null) {
socket.close(); // 关闭套接字
}
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
}