现在的我太阳穴隐隐生疼,一直疼到了脑后,而后又有梗塞的钝痛,从胸中蔓延开去,看了一眼时间,凌晨3:43,又望了望阳台,运气真不好,外面是一片漆黑,并没有哈弗大学说的凌晨4点钟的太阳。此时室友翻了一下身,好吧,我好像又吵醒她了。很想上床去,可是胸中的疼痛,酸涩,喜悦真的太汹涌了,就要溢出来,止不住了。
子在川上曰:逝者如斯夫,不舍昼夜。-《子罕》
突然很想回到旧时光,跟那个自卑敏感的自己说一声“其实QQ也没什么,不用为此而羞愧。”现在是炙热的8月,那么2007年的8月我在干什么呢,当时的我刚上三年级,放暑假了,应该宅是在家里看电视,也没什么稀奇的。可是如果再往前三四个月呢?那时的我第一次知道了QQ这个新奇的玩意儿,身边的同学都在聊它,我很想加入他们,可是怎么都插不上话。原因很简单,因为当时我家里没有电脑。那时的我还不知道自卑这个词,只是突然感觉胸口有点疼,有点想逃离教室。
时间再往后一年吧,我家里终于有了一台电脑,还连上了网线,我和我弟弟很开心地注册了一个QQ,两个人天天一放学就急急忙忙地赶回家玩QQ宠物,还傻傻地和网上的一个网友聊的很开心。QQ让我有了和同学们交流的勇气,让我心中那不知名的酸涩可以暂时退散。
时间回到现在,我自己可以用JAVA写一个简易版的QQ,我只想说:那些曾经让你的岁月暗淡无光的东西,那些曾经让你觉得高深复杂无法理解的东西,那些曾经让你莫名酸涩的东西,最终都会在时光的流逝中揭开它的神秘面纱。然后放任你大哭一场,徒叹一句:当初的自己很傻很天真......
好了,不说了。现在我们假设都是一名优秀的外科医生,让我们先来肢解QQ这只小企鹅的心脏——服务器和客户机吧。先看一下它的大体框架 ,真的很简单。
A.服务器
1.创建一个服务器
2.创建一个Socket甬道
3.从Socket甬道中获取输入和输出流,再对输入和输出流进行读写操作。
4.关闭服务器与客户机的连接
B.客户机
1.创建一个Socket甬道(指定服务器的ip和port)
2.从Socket甬道中获取输入和输出流,再对输入和输出流进行读写操作。
3.关闭客户机与服务器的连接
然后戴上手套,拿起手术刀,开始吧!
A.服务器
1.画一个界面
// 1.画一个界面// 设置大小this.setSize(500, 500);// 布局this.setLayout(new FlowLayout());// 标题this.setTitle("服务器1");
1.1多行输入框内的消息为聊天记录(也就是1.服务器发送给客户机的消息,2.客户机发送给服务器的消息都要显示),用滚动条jscrollPane来阅读JTextArea
jtfRec = new JTextArea(10, 40);jscrollPane = new JScrollPane(jtfRec);this.add(jscrollPane);
1.2单行文本输入框内的消息为服务器发送给客户机的消息
jtfSend = new JTextField(40);this.add(jtfSend);
1.3由点击按钮这个事件来发送消息
JButton Sendbutton = new JButton("发送");Sendbutton.addActionListener(this);this.add(Sendbutton);
2.创建一个服务器
2.1创建一个服务器(要记得给定端口)
// 2.1创建一个服务器(要记得给定端口)server = new ServerSocket(port);System.out.println("1.成功创建服务器" + port);
2.2创建一个Socket甬道来获取输入和输出流,用循环来让服务器可以不停地连接客户机
// 2.2创建一个Socket甬道来获取输入和输出流 Socket socket;// 用循环来让服务器可以不停地连接客户机 while (true) {System.out.println("2.等待客户机进入");socket = server.accept();//从请求连接队列里取出一个连接也就是让服务器进入阻塞状态 System.out.println("3.已有客户机登录");// 用线程对输入和输出流进行读写操作 ct4 = new ChatThreadV4(socket,jtfSend,jtfRec);ct4.start();System.out.println("4.循环结束了一次");}
2.3接收消息(用一个线程来对输入流进行处理)
2.3.1 首先定义一个方法readString来把客户机发来的输入流转为字符串
public String readString(InputStream ins) throws IOException {reader = new BufferedReader(new InputStreamReader(ins));return reader.readLine();}
2.3.2 调用方法readString,用一个字符串来封装获得的字符串,并显示在JTextArea中,用一个判断条件来使服务器和客户机的通信在适当的时候停止
private void processChat() throws IOException {//服务器给客户机发送欢迎登陆的消息: String s = "hello,欢迎登录服务器2.0\r\n";// 用一个字节数组来封装,也可不封装 byte[] data = s.getBytes();// 取得组成这个字符串的字节 out.write(data);out.flush();// 2.对输入流进行处理(内有大文章) // 2.1此时的处理是将输入流的字节转为字符串 String inputs = readString(ins);// 2.2用一个判断条件来使服务器和客户机的通信在适当的时候停止 while (!inputs.equals("bye")) {//2.3服务器显示客户机发来的消息(除了用打印语句还可以用JTextAre多行输入框)// System.out.println("客户机说:" + inputs); Chatlog += "(服务器显示接收的消息)客户机说:" + inputs+"\r\n";jtfRec.setText(Chatlog);//发送消息可以另外用一个方法(输入框) // 2.5读取客户机的下一次输入 inputs = readString(ins);}//2.6当通信到了停止的时候,服务器向客户机发送再见的消息 s = "再见,欢迎再来哦!\r\n";data = s.getBytes();// 取得组成这个字符串的字节 out.write(data);out.flush();//2.7 关闭与客户机的连接 socket.close();}//2.3接收消息 public void run() {try {processChat();} catch (IOException e) {// TODO Auto-generated catch block e.printStackTrace();}}
2.4发送消息
2.4.1用一个字符串来封装要发送的消息(可以用JTextField,或别的方法来决定要发送的消息),然后用out.write()发送
2.4.2在服务器的JTextArea中显示服务器发送的消息
//2.4发送消息 public void sendMsg(String msg) {//2.4.1将服务器发送的消息显示出来 String s1 ="服务器说:"+msg+"\r\n";Chatlog +=s1;jtfRec.setText(Chatlog);//发送 String s2 =msg+"\r\n";try{byte[] ba =s2.getBytes();out.write(ba);}catch(Exception e){e.printStackTrace();}}
B.客户机
1.画一个界面
1.1 多行输入框内的消息为聊天记录(也就是1.服务器发送给客户机的消息,2.客户机发送给服务器的消息都要显示),用滚动条jscrollPane来阅读JTextArea
1.2 单行文本输入框内的消息为客户机发送给服务器的消息
1.3 由点击Linkbutton按钮这个事件来连接服务器
1.3 由点击Sendbutton按钮这个事件来发送消息
2. 创建一个socket连接服务器
2.1 连接服务器(记得指定服务器的ip和端口)
2.2 接收消息(用一个线程来对输入流进行处理)
2.2.1 首先定义一个方法readString来把客户机发来的输入流转为字符串
2.2.2 调用方法readString,用一个字符串来封装获得的字符串,并显示在JTextArea中,用一个判断条件来使服务器和客户机的通信在适当的时候停止
2.3 发送消息
2.3.1用一个字符串来封装要发送的消息(可以用JTextField,或别的方法来决定要发送的消息),然后用out.write()发送
2.3.2在服务器的JTextArea中显示服务器发送的消息
最后我把源代码贴上吧!
这是服务器的
import java.awt.FlowLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JScrollPane;import javax.swing.JTextArea;import javax.swing.JTextField;//给服务器加一个界面public class ChatServerV4 extends JFrame implements ActionListener {ServerSocket server;JTextField jtfSend;JTextArea jtfRec;JScrollPane jscrollPane;ChatThreadV4 ct4;// 初始化 public void initUI(int port) throws IOException {// 1.画一个界面 // 设置大小 this.setSize(500, 500);// 布局 this.setLayout(new FlowLayout());// 标题 this.setTitle("服务器1");多行输入框内的消息为聊天记录(也就是1.服务器发送给客户机的消息,2.客户机发送给服务器的消息都要显示)jtfRec = new JTextArea(10, 40);// this.add(jtfRec); //滚动条来阅读JTextArea jscrollPane = new JScrollPane(jtfRec);this.add(jscrollPane);// 1.2单行文本输入框内的消息为服务器发送给客户机的消息 // 内部类调用的对象要用Final jtfSend = new JTextField(40);this.add(jtfSend);// 1.3由点击按钮这个事件来发送消息 JButton Sendbutton = new JButton("发送");Sendbutton.addActionListener(this);this.add(Sendbutton);// 可视 this.setVisible(true);// 2.1创建一个服务器(要记得给定端口) server = new ServerSocket(port);System.out.println("1.成功创建服务器" + port);// 2.2创建一个Socket甬道来获取输入和输出流 Socket socket;// 用循环来让服务器可以不停地连接客户机 while (true) {System.out.println("2.等待客户机进入");socket = server.accept();//从请求连接队列里取出一个连接也就是让服务器进入阻塞状态 System.out.println("3.已有客户机登录");// 用线程对输入和输出流进行读写操作 ct4 = new ChatThreadV4(socket,jtfSend,jtfRec);ct4.start();System.out.println("4.循环结束了一次");}}// 主函数 public static void main(String[] args) throws IOException {ChatServerV4 cs4 = new ChatServerV4();cs4.initUI(8888);}public void actionPerformed(ActionEvent arg0) {String msg = jtfSend.getText();ct4.sendMsg(msg);jtfSend.setText("");}}import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.net.Socket;import javax.swing.JTextArea;import javax.swing.JTextField;public class ChatThreadV4 extends Thread {private Socket socket;private InputStream ins;private OutputStream out;private BufferedReader reader;JTextField jtfSend;JTextArea jtfRec;private String Chatlog="客户机已连接成功\r\n";// 构造器 public ChatThreadV4(Socket socket, JTextField jtfSend,JTextArea jtfRec) throws IOException {this.socket = socket;this.jtfSend =jtfSend;this.jtfRec = jtfRec;// 实例化 输入和输出流 this.ins = socket.getInputStream();this.out = socket.getOutputStream();}//2.3接收消息 public void run() {try {processChat();} catch (IOException e) {// TODO Auto-generated catch block e.printStackTrace();}}/** * 处理连接对象:读取客户机发来的字符串,回送给客户机 * * @throws IOException */private void processChat() throws IOException {//服务器给客户机发送欢迎登陆的消息: String s = "hello,欢迎登录服务器2.0\r\n";// 用一个字节数组来封装,也可不封装 byte[] data = s.getBytes();// 取得组成这个字符串的字节 out.write(data);out.flush();// 2.对输入流进行处理(内有大文章) // 2.1此时的处理是将输入流的字节转为字符串 String inputs = readString(ins);// 2.2用一个判断条件来使服务器和客户机的通信在适当的时候停止 while (!inputs.equals("bye")) {//2.3服务器显示客户机发来的消息(除了用打印语句还可以用JTextAre多行输入框)// System.out.println("客户机说:" + inputs); Chatlog += "(服务器显示接收的消息)客户机说:" + inputs+"\r\n";jtfRec.setText(Chatlog);//发送消息可以另外用一个方法(输入框) // 2.5读取客户机的下一次输入 inputs = readString(ins);}//2.6当通信到了停止的时候,服务器向客户机发送再见的消息 s = "再见,欢迎再来哦!\r\n";data = s.getBytes();// 取得组成这个字符串的字节 out.write(data);out.flush();//2.7 关闭与客户机的连接 socket.close();}//2.3.1 首先定义一个方法来把客户机发来的输入流转为字符串 /*** 从输入流对象中读取字节,拼成字符串返回 给一个可以认为字符串结束的结束符:如果读到字节为13(回车符),则认为在回车符以前的是一个字符串 * * @param ins * 输入流对象 * @return 从流上(客户机)读到的字符串 * @throws IOException */public String readString(InputStream ins) throws IOException {reader = new BufferedReader(new InputStreamReader(ins));return reader.readLine();}//2.4发送消息 public void sendMsg(String msg) {//2.4.1将服务器发送的消息显示出来 String s1 ="服务器说:"+msg+"\r\n";Chatlog +=s1;jtfRec.setText(Chatlog);//发送 String s2 =msg+"\r\n";try{byte[] ba =s2.getBytes();out.write(ba);}catch(Exception e){e.printStackTrace();}}}
这是客户机的
import java.awt.FlowLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JScrollPane;import javax.swing.JTextArea;import javax.swing.JTextField;//给客户机加一个界面public class ClientV2<Final> extends JFrame {JTextField jtfSend;JTextArea jtfRec;JScrollPane jscrollPane;Socket socket;ClientThreadV2 cThread2;// 初始化public void initUI() throws IOException {// 1.画一个界面// 设置大小this.setSize(500, 500);// 布局this.setLayout(new FlowLayout());// 标题this.setTitle("客户机2.0");// 1.1多行输入框内的消息为聊天记录(也就是1.服务器发送给客户机的消息,2.客户机发送给服务器的消息都要显示)jtfRec = new JTextArea(10, 40);// this.add(jtfRec);// 滚动条来阅读JTextAreajscrollPane = new JScrollPane(jtfRec);this.add(jscrollPane);// 1.2单行文本输入框内的消息为服务器发送给客户机的消息jtfSend = new JTextField(40);this.add(jtfSend);// 1.3由点击按钮这个事件来连接服务器JButton Linkbutton = new JButton("连接服务器");this.add(Linkbutton);// 1.4由点击按钮这个事件来触发通信JButton Sendbutton = new JButton("发送");this.add(Sendbutton);// 可视this.setVisible(true);// 2.创建一个socket连接服务器// 2.1 连接(用内部类给按钮加监听器,内部类用到的对象用final)Linkbutton.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {String ip = "192.168.10.65";int port = 8888;System.out.println("即将连接到服务器:" + ip + "port:" + port);try {// 创建一个Socket甬道(指定服务器的ip和port)socket = new java.net.Socket(ip, port);cThread2 = new ClientThreadV2(jtfSend, jtfRec,socket);//2.2接收消息cThread2.start();javax.swing.JOptionPane.showMessageDialog(null, "连接成功");} catch (Exception e1) {javax.swing.JOptionPane.showMessageDialog(null, "连接失败");}}});// 2.3发送消息(用内部类给按钮加监听器,内部类用到的对象用final)Sendbutton.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {String msg = jtfSend.getText();cThread2.sendMsg(msg);jtfSend.setText("");}});}// 主函数public static void main(String[] args) throws IOException {ClientV2 cV2 = new ClientV2();cV2.initUI();}}import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.net.Socket;import javax.swing.JTextArea;import javax.swing.JTextField;public class ClientThreadV2 extends Thread {Socket socket;private java.io.InputStream ins;private java.io.OutputStream out;private BufferedReader reader;private String Chatlog = "成功登录服务器\r\n";JTextField jtfSend;JTextArea jtfRec;// 构造器public ClientThreadV2(JTextField jtfSend, JTextArea jtfRec,Socket socket) throws IOException {this.socket=socket;this.jtfSend = jtfSend;this.jtfRec = jtfRec;// 实例化 输入和输出流(必须在构造器中先实例化ins和out,不然会有空指针)this.ins = socket.getInputStream();this.out = socket.getOutputStream();}// 2.2接收消息(用线程)public void run() {try {ReadMsg();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}// 2.2接收消息 (对输入流进行处理)public void ReadMsg() throws IOException {System.out.println("1111111111111111111");// 2.2.1此时的处理是将输入流的字节转为字符串String inputs = readString(ins);// 2.2.2用一个判断条件来使服务器和客户机的通信在适当的时候停止while (!inputs.equals("bye")) {// 2.2.3客户机显示服务器发来的消息(除了用打印语句还可以用JTextAre多行输入框)// System.out.println("服务器说:" + inputs);Chatlog += "(客户机显示接收的消息 )服务器说:" + inputs + "\r\n";jtfRec.setText(Chatlog);// 2.2.4读取客户机的下一次输入inputs = readString(ins);}//2.2.5当通信到了停止的时候,服务器向客户机发送再见的消息String s = "再见,欢迎再来哦!\r\n";byte[] data = s.getBytes();// 取得组成这个字符串的字节out.write(data);out.flush();//2.7 关闭与客户机的连接socket.close();}/*** 从输入流对象中读取字节,拼成字符串返回 给一个可以认为字符串结束的结束符:如果读到字节为13(回车符),则认为在回车符以前的是一个字符串** @param ins* 输入流对象* @return 从流上(客户机)读到的字符串* @throws IOException*/public String readString(InputStream ins) throws IOException {reader = new BufferedReader(new InputStreamReader(ins));return reader.readLine();}// 2.3发送消息public void sendMsg(String msg) {// 将客户机发送的消息显示出来String s1 = "客户机2.0说:"+msg + "\r\n";Chatlog += s1;jtfRec.setText(Chatlog);// 发送String s2 =msg + "\r\n";try {byte[] ba = s2.getBytes();out.write(ba);} catch (Exception e) {e.printStackTrace();}
暂无评论数据