[size=x-large][b]通信学习[/b][/size]
学习通信,从兴趣开始,之前我也尝试过自己弄一个C++的通信,买了相关的书籍,一步一步的做下去,开始时做的还有模有样,实现了基本的对话功能,但是后来,当我想实现更多功能时,发现自己编变得无从下手,第一是因为书籍问题(已知没有找到关于通信的系统的书籍),第二是我对C++的编程习惯不感冒,于是我就走向了java的通信设计中去。
[size=medium][color=darkblue]首先,明确目标:做一个既可以对话又可以发图片(当然是可以群聊的)的聊天系统;
再来便是明确实施步骤,1.先是做个服务端,可以先让电脑上的telnet来充当客户端,能实现Eclipse的控制台与telnet对话;2.做个客户端界面,不必做的太过于复杂,有输入和显示功能即可,也就是相当于把这个客户端当做telnet实现对话;3.利用线程来实现多个客户端的对话;4.实现发送图片等功能,并可以自己加上自己喜欢的功能!好了,说了那么多,接下来就请看代码:[/color][/size]
[color=red][size=large][b]这是服务端代码,用于开启服务器[/b][/size][/color]
[color=red][size=large][b]这是服务器的线程,实现数据的传输[/b][/size][/color]
[color=red][size=large][b]这是客户端代码,用于设计界面和实现功能[/b][/size][/color]
[color=red][size=large][b]这是客户端线程代码[/b][/size][/color]
[color=red][size=large][b]这是客户端接口代码[/b][/size][/color]
[img]http://dl2.iteye.com/upload/attachment/0102/7251/274d7ac5-e075-334c-a608-630ba0cc4b64.png[/img]
[size=large][color=cyan][b]最后,总结一下,每个人都会犯错误,我也一样,本程序中,在你打开客户端界面时,必须得先输入名字,若是手一抖先绘图了,程序就会报错哦。本次通信未能实现文件传输功能,现在上传主要是为了方便通信新手来观看,指导,如果有错误,欢迎留言!!最后喝杯茶来结束我今天的技术博客报告 :arrow: [/b][/color][/size]
学习通信,从兴趣开始,之前我也尝试过自己弄一个C++的通信,买了相关的书籍,一步一步的做下去,开始时做的还有模有样,实现了基本的对话功能,但是后来,当我想实现更多功能时,发现自己编变得无从下手,第一是因为书籍问题(已知没有找到关于通信的系统的书籍),第二是我对C++的编程习惯不感冒,于是我就走向了java的通信设计中去。
[size=medium][color=darkblue]首先,明确目标:做一个既可以对话又可以发图片(当然是可以群聊的)的聊天系统;
再来便是明确实施步骤,1.先是做个服务端,可以先让电脑上的telnet来充当客户端,能实现Eclipse的控制台与telnet对话;2.做个客户端界面,不必做的太过于复杂,有输入和显示功能即可,也就是相当于把这个客户端当做telnet实现对话;3.利用线程来实现多个客户端的对话;4.实现发送图片等功能,并可以自己加上自己喜欢的功能!好了,说了那么多,接下来就请看代码:[/color][/size]
[color=red][size=large][b]这是服务端代码,用于开启服务器[/b][/size][/color]
package 通信聊天;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
//0-65535
public void setup(int port){
//服务器套接字
try {
ServerSocket ss = new ServerSocket(port);
System.out.println("监听端口"+port+"成功!");
while(true){
//阻塞
Socket socket = ss.accept();
System.out.println("有人访问了");
ServerThread st = new ServerThread(socket);
st.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Server().setup(8888);
}
}
[color=red][size=large][b]这是服务器的线程,实现数据的传输[/b][/size][/color]
package 通信聊天;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.ArrayList;
public class ServerThread extends Thread {
//保存所有客户端的线程
private static ArrayList<ServerThread> list = new ArrayList<ServerThread>();
private Socket socket;
private String name;
private OutputStream output;
private DataOutputStream dos;
public ServerThread(Socket socket){
this.socket = socket;
list.add(this);
}
public void run(){
try {
InputStream input = socket.getInputStream();
output = socket.getOutputStream();
dos = new DataOutputStream(output);
//向客户端发送信息
String str = "请输入您的名字:\r\n";
sendMsg(str);
name = readLine(input);
//数据流
DataInputStream dis = new DataInputStream(input);
while(true){
int type = dis.readInt();
if(type == 1){
//接收数据包的长度
int len = dis.readInt();
//接收数据包内容的数组
byte[] bytes = new byte[len];
//把读到的数据填到bytes里面
dis.readFully(bytes);
String line = new String(bytes,"GBK");
System.out.println("Recv:"+line);
//向所有的客户端广播信息
for(int i=0; i<list.size(); i++){
ServerThread st = list.get(i);
st.sendMsg(name+"说:"+line);
}
} else if(type == 2){
//接收线条
int len = dis.readInt();
int x1 = dis.readInt();
int y1 = dis.readInt();
int x2 = dis.readInt();
int y2 = dis.readInt();
for(int i=0; i<list.size(); i++){
ServerThread st = list.get(i);
st.dos.writeInt(2);
st.dos.writeInt(len);
st.dos.writeInt(x1);
st.dos.writeInt(y1);
st.dos.writeInt(x2);
st.dos.writeInt(y2);
}
} else if(type == 3){
//接收图片
int len = dis.readInt();
byte[] bytes = new byte[len];
dis.readFully(bytes);
System.out.println("Server recvpic "+bytes.length);
//
for(int i=0; i<list.size(); i++){
ServerThread st = list.get(i);
st.dos.writeInt(3);
st.dos.writeInt(len);
st.dos.write(bytes);
}
}
}
} catch (Exception ex){
ex.printStackTrace();
}
}
public void sendMsg(String str) throws IOException{
str += "\r\n";
byte[] bytes = str.getBytes("GBK");
int len = bytes.length;
//发送消息包的类型:1.文本,2.文件,3.图片
dos.writeInt(1);
//先发送数据的长度
dos.writeInt(len);
//再发送数据内容
dos.write(bytes);
}
public String readLine(InputStream input) throws IOException{
//字节队列
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while(true){
int n = input.read();
if(n == '\r')
continue;
if(n == '\n'){
break;
}
//把每一个字节存入队列
bos.write(n);
}
byte[] bytes = bos.toByteArray();
//把字节还原成字符串
String content = new String(bytes, "GBK");
return content;
}
}
[color=red][size=large][b]这是客户端代码,用于设计界面和实现功能[/b][/size][/color]
package 客户端;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
public class Client implements MsgListener{
private JTextPane log2 ;
public JPanel jpa;
private Document doc;
ClientThread ct = new ClientThread();
final JFrame jf = new JFrame("QQ聊天");
public void initUI(){
jf.setDefaultCloseOperation(3);
jf.setLocation(100, 100);
jf.setLayout(new FlowLayout());
jf.setResizable(false);
jf.setSize(900, 500);
//放置图片的地方
log2 = new JTextPane();
JScrollPane js2 =new JScrollPane(log2);
log2.setEditable(false);
log2.setPreferredSize( new Dimension(860,180));
doc = log2.getDocument();
jf.add(js2);
final JTextField input = new JTextField(65);
jf.add(input);
jpa =new JPanel();
jpa.setPreferredSize(new Dimension(860,230));
jpa.setBackground(Color.PINK);
JButton btn = new JButton("Send");
jf.add(btn);
JButton btn0 = new JButton("Pic");
jf.add(btn0);
JLabel jla = new JLabel("绘图区");
jpa.add(jla);
jf.add(jpa);
jf.setVisible(true);
jf.addMouseListener(ma);
jpa.addMouseListener(ma);
jpa.addMouseMotionListener(ma);
ct.addMsgListener(this);
ct.start();
btn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
String msg = input.getText();
input.setText("");
try {
ct.sendMsg(msg);
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
btn0.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser jc = new JFileChooser();
jc.showOpenDialog(jf);
File file = jc.getSelectedFile();
try {
FileInputStream fis = new FileInputStream(file);
byte[] bytes = new byte[fis.available()];
fis.read(bytes);
fis.close();
ct.sendImg(bytes);
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
}
MouseAdapter ma = new MouseAdapter() {
int x1,x2,y1,y2;
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
}
public void mouseReleased(MouseEvent e) {
x2 = e.getX();
y2 = e.getY();
try {
//把线条的两个点发送到服务器
ct.sendLine(x1, y1, x2, y2);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
public void mouseDragged(MouseEvent e){
x2 = e.getX();
y2 = e.getY();
try {
//把线条的两个点发送到服务器
ct.sendLine(x1, y1, x2, y2);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
x1 = x2;
y1 = y2;
}
};
public static void main(String[] args) {
new Client().initUI();
}
public void onRecvMsg(String msg){
Document doc = log2.getDocument();
try {
doc.insertString(doc.getLength(), msg+"\r\n", null);
} catch (BadLocationException e) {
e.printStackTrace();
}
//log.append(msg+"\r\n");
}
public void onRecvLine(int x1, int y1, int x2, int y2) {
jpa.getGraphics().drawLine(x1, y1, x2, y2);
}
public void onRecvPic(byte[] bytes) {
ByteArrayInputStream input = new ByteArrayInputStream(bytes);
try {
BufferedImage img = ImageIO.read(input);
ImageIcon icon = new ImageIcon(img);
log2.setCaretPosition(doc.getLength());
log2.insertIcon(icon);
Document doc = log2.getDocument();
try {
doc.insertString(doc.getLength(), "\r\n", null);
} catch (BadLocationException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
[color=red][size=large][b]这是客户端线程代码[/b][/size][/color]
package 客户端;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
public class ClientThread extends Thread {
private OutputStream output;
DataOutputStream dos;
private ArrayList<MsgListener> list = new ArrayList<MsgListener>();
public void addMsgListener(MsgListener listener){
list.add(listener);
}
}
public void sendLine(int x1,int y1,int x2,int y2) throws IOException{
dos.writeInt(2);
int len = 16;
dos.writeInt(len);
dos.writeInt(x1);
dos.writeInt(y1);
dos.writeInt(x2);
dos.writeInt(y2);
}
public void sendImg(byte[] bytes) throws IOException{
dos.writeInt(3);
dos.writeInt(bytes.length);
//再发送数据内容
dos.write(bytes);
}
public void sendMsg(String str) throws IOException{
str += "\r\n";
byte[] bytes = str.getBytes("GBK");
int len = bytes.length;
//发送消息包的类型:1.文本,2.线条,3.图片
dos.writeInt(1);
//先发送数据的长度
dos.writeInt(len);
//再发送数据内容
dos.write(bytes);
}
}
public void run(){
try {
Socket socket = new Socket("127.0.0.1", 8888);
InputStream input = socket.getInputStream();
output = socket.getOutputStream();
dos = new DataOutputStream(output);
DataInputStream dis = new DataInputStream(input);
while(true){
int type = dis.readInt();
if(type == 1){
//接收数据包的长度
int len = dis.readInt();
//接收数据包内容的数组
byte[] bytes = new byte[len];
//把读到的数据填到bytes里面
dis.readFully(bytes);
String line = new String(bytes,"GBK");
for(int i=0; i<list.size(); i++){
list.get(i).onRecvMsg(line);
}
} else if(type == 2){
//接收线条
int len = dis.readInt();
int x1 = dis.readInt();
int y1 = dis.readInt();
int x2 = dis.readInt();
int y2 = dis.readInt();
for(int i=0; i<list.size(); i++){
list.get(i).onRecvLine(x1, y1, x2, y2);
}
}else if(type == 3){
//接收图片
int len = dis.readInt();
byte[] bytes = new byte[len];
//把读到的数据填到bytes里面
dis.readFully(bytes);
//
for(int i=0; i<list.size(); i++){
list.get(i).onRecvPic(bytes);
}
}
listener.onRecvMsg(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public String readLine(InputStream input) throws IOException{
//字节数组队列
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while(true){
int n = input.read();
if(n == '\r')
continue;
if(n == '\n'){
break;
}
//把收到的字节存到队列中
bos.write(n);
}
byte[] bytes = bos.toByteArray();
String content = new String(bytes, "GBK");
return content;
}
}
[color=red][size=large][b]这是客户端接口代码[/b][/size][/color]
package 客户端;
public interface MsgListener {
public void onRecvMsg(String msg);
public void onRecvLine(int x1,int y1,int x2,int y2);
public void onRecvPic(byte[] bytes);
}
[img] :lol:
[img]http://dl2.iteye.com/upload/attachment/0102/7251/274d7ac5-e075-334c-a608-630ba0cc4b64.png[/img]
[size=large][color=cyan][b]最后,总结一下,每个人都会犯错误,我也一样,本程序中,在你打开客户端界面时,必须得先输入名字,若是手一抖先绘图了,程序就会报错哦。本次通信未能实现文件传输功能,现在上传主要是为了方便通信新手来观看,指导,如果有错误,欢迎留言!!最后喝杯茶来结束我今天的技术博客报告 :arrow: [/b][/color][/size]