最近学到了Socket通信,其实在学校的课程--计算机网络,这个东西是必学的。。。只是自己上课没听,只为
应付考试,这个也没怎么碰触。接触到这个,现在就讲一下最简单的聊天通信C/S模式的代码的编写。
这里只谈一下最简单的C/S模式的
聊天程序。
显然分为客户端和服务器端。
流程也很简单。
服务端首先需要
监听摸一个端口号。(由于1024以内的端口计算机通常内部程序在使用,所以我们最好监听端口号较大的。以8888为例。)
//监听端口号为8888端口
ServerSocket ss = new ServerSocket(8888);
//等待客户端的访问
Socket
socket = ss.accept();
这个时候客户端访问该端口
Socket socket = new Socket("localhost",8888);
或者:
Socket socket = new Socket("127.0.0.1",8888);
这个时候两者的连接已经建立。
怎么交换信息呢?在Socket中,无论是客户端还是服务器都是从socket.getInputStream()中获取到对方的信息,而将自己需要发送的信息写入到socket.getOutputStream()中。
总结上面的也就是说,我们只需要建立连接,然后从socket.getInputStream()读取对方发送的信息,将自己需要发送的信息写入到socket.getOutputStream()中去
快递给对方。
再谈谈多
线程。
当需要启动多个客户端时,客户端的
编码部分是没有变化的。只需要改变服务器端。
我们来观察整个通信过程,
发现服务器端等待客户端接入时,执行ss.accept()来接受到客户端的Socket。但是当启动第二个时,就没有执行ss.accept()了。所以我们需要无限
循环来一直接受客户端的接入(因为不知道有多少个客户端,所以就一直循环)。然后启动线程进行消息的接受与发送。(写一个线程类,重写run方法,将之前的接受与发送消息的代码直接复制就行了)
具体代码如下:
服务器:
单线程:
class="java" name="code">package 群聊;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Server {
JTextArea jtx_output;
JTextArea jtx_input;
InputStream input;
OutputStream output;
/**
* 群聊服务器
* @param args
* @throws MalformedURLException
*/
public static void main(String[] args) throws MalformedURLException {
// TODO 自动生成的方法存根
new Server().showUI();
}
public void showUI() throws MalformedURLException {
JFrame jf = new JFrame();
jf.setTitle("群聊服务器");
jf.setSize(new Dimension(420, 480));
jf.setResizable(false);// 设置窗体大小不能改变
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(3);
JPanel jpL = new JPanel();
jpL.setPreferredSize(new Dimension(300, 400));
JPanel jpR = new JPanel();
jpR.setPreferredSize(new Dimension(100, 400));
//设置带自动换行的只读文本区域
jtx_output = new JTextArea();
//不可编辑,只读文本
jtx_output.setEditable(false);
//jtx_input.setLineWrap(true);
JScrollPane sp1 = new JScrollPane(jtx_output);
sp1.setPreferredSize(new Dimension(300, 315));
jpL.add(sp1);
//设置头像显示按钮
JButton jb = new JButton(new ImageIcon("images/头像1.jpg"));
jpR.add(jb);
//设置可输入自动换行的文本区域
jtx_input = new JTextArea();
// jtx_input.setLineWrap(true);
JScrollPane sp2 = new JScrollPane(jtx_input);
sp2.setPreferredSize(new Dimension(300, 100));
jpL.add(sp2);
//设置头像显示按钮
JButton jb1 = new JButton(new ImageIcon("images/头像.JPEG"));
jpR.add(jb1);
JButton Jb = new JButton("发送");
jf.add(jpL, BorderLayout.WEST);
jf.add(jpR, BorderLayout.EAST);
jf.add(Jb, BorderLayout.SOUTH);
jf.setVisible(true);
// 新建一个服务器套接字
try {
ServerSocket ss = new ServerSocket(8888);
System.out.println("监听端口8888成功!");
jtx_output.append("监听端口8888成功!");
// 等待客户端的访问
Socket socket = ss.accept();
input = socket.getInputStream();
output = socket.getOutputStream();
//点击发送按钮,将服务器端的消息发送到客户端
Jb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String out = jtx_input.getText()+"\n";
jtx_output.append("服务器说 :"+out);
//将服务器段的消息发送给客户端
try {
byte[] bytes = out.getBytes("GBK");
try {
output.write(bytes);
output.flush();
} catch (IOException e1) {
}
} catch (UnsupportedEncodingException e1) {
}
}
});
// String msg = "Hello, 你好!聊天开始!";
// jtx_output.append(msg);
// //写到客户端
// byte[] bytes = msg.getBytes("GBK");
// output.write(bytes);
//接受客户端发来的消息
while (true) {
String line = readLine(input);
jtx_output.append("客户端说 :"+line+"\n");
}
} catch (IOException e) {
}
}
// 用来读取中文的方法
public String readLine(InputStream input) throws IOException {
// 字节输出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while (true) {
int n = input.read();
// 以换行符为读取的间隔
if (n == '\n')
break;
bos.write(n);
}
byte[] bytes = bos.toByteArray();
return new String(bytes, "GBK");
}
}
多线程:
(1)主类
package 群聊;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class ServerThread {
JTextArea jtx_output;
JTextArea jtx_input;
/**
* 群聊服务器多线程
* @param args
* @throws MalformedURLException
*/
public static void main(String[] args) throws MalformedURLException {
// TODO 自动生成的方法存根
new ServerThread().showUI();
}
public void showUI() throws MalformedURLException {
JFrame jf = new JFrame();
jf.setTitle("群聊服务器");
jf.setSize(new Dimension(420, 480));
jf.setResizable(false);// 设置窗体大小不能改变
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(3);
JPanel jpL = new JPanel();
jpL.setPreferredSize(new Dimension(300, 400));
JPanel jpR = new JPanel();
jpR.setPreferredSize(new Dimension(100, 400));
//设置带自动换行的只读文本区域
jtx_output = new JTextArea();
// 不可编辑,只读文本
jtx_output.setEditable(false);
// jtx_input.setLineWrap(true);
JScrollPane sp1 = new JScrollPane(jtx_output);
sp1.setPreferredSize(new Dimension(300, 315));
jpL.add(sp1);
// 设置头像显示按钮
JButton jb = new JButton(new ImageIcon("images/头像1.jpg"));
jpR.add(jb);
// 设置可输入自动换行的文本区域
jtx_input = new JTextArea();
// jtx_input.setLineWrap(true);
JScrollPane sp2 = new JScrollPane(jtx_input);
sp2.setPreferredSize(new Dimension(300, 100));
jpL.add(sp2);
// 设置头像显示按钮
JButton jb1 = new JButton(new ImageIcon("images/头像.JPEG"));
jpR.add(jb1);
JButton Jb = new JButton("发送");
jf.add(jpL, BorderLayout.WEST);
jf.add(jpR, BorderLayout.EAST);
jf.add(Jb, BorderLayout.SOUTH);
jf.setVisible(true);
int i=0;
// 新建一个服务器套接字
try {
ServerSocket ss = new ServerSocket(8888);
jtx_output.append("监听端口8888成功!\n");
// 循环多个客户端访问
while (true) {
i++;
// 接受到客户端的访问
Socket socket = ss.accept();
// 启动线程来搭建和该客户端的连接
SocketThread st = new SocketThread(socket,Jb,jtx_input,jtx_output,i);
st.start();
}
} catch (IOException e) {
}
}
}
(2)线程类
package 群聊;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JTextArea;
public class SocketThread extends Thread {
public Socket socket;
InputStream input;
OutputStream output;
int i;
JButton Jb;
JTextArea jtx_output;
JTextArea jtx_input;
// 构造方法传递客户端的socket
public SocketThread(Socket scoket, JButton Jb, JTextArea jtx_input,
JTextArea jtx_output, int i) {
this.socket = scoket;
this.Jb = Jb;
this.jtx_input = jtx_input;
this.jtx_output = jtx_output;
this.i = i;
}
// 重写线程run方法
public void run() {
try {
input = socket.getInputStream();
} catch (IOException e2) {
}
try {
output = socket.getOutputStream();
} catch (IOException e2) {
}
String outsay = "客户端" + i + "你好!"+"\n";
byte[] bytess;
try {
bytess = outsay.getBytes("GBK");
output.write(bytess);
} catch (UnsupportedEncodingException e3) {
// TODO 自动生成的 catch 块
e3.printStackTrace();
} catch (IOException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
// 点击发送按钮,将服务器端的消息发送到客户端
Jb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String out = jtx_input.getText() + "\n";
jtx_output.append("服务器说 :" + out+"\n");
// 将服务器段的消息发送给客户端
try {
byte[] bytes = out.getBytes("GBK");
try {
output.write(bytes);
output.flush();
} catch (IOException e1) {
}
} catch (UnsupportedEncodingException e1) {
} catch (IOException e2) {
e2.printStackTrace();
}
}
});
// 接受客户端发来的消息
while (true) {
try {
String line = readLine(input);
jtx_output.append("客户端" + i + "说 :" + line + "\n");
} catch (IOException e1) {
}
}
}
// 用来读取中文的方法
public String readLine(InputStream input) throws IOException {
// 字节输出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while (true) {
int n = input.read();
// 以换行符为读取的间隔
if (n == '\n')
break;
bos.write(n);
}
byte[] bytes = bos.toByteArray();
return new String(bytes, "GBK");
}
}
客户端:
package 群聊;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Client {
JTextArea jtx_output;
JTextArea jtx_input;
InputStream input;
OutputStream output;
/**
* @param args
* @throws MalformedURLException
*/
public static void main(String[] args) throws MalformedURLException {
// TODO 自动生成的方法存根
new Client().showUI();
}
public void showUI() throws MalformedURLException {
JFrame jf = new JFrame();
jf.setTitle("群聊客户器");
jf.setSize(new Dimension(420, 480));
jf.setResizable(false);// 设置窗体大小不能改变
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(3);
JPanel jpL = new JPanel();
jpL.setPreferredSize(new Dimension(300, 400));
JPanel jpR = new JPanel();
jpR.setPreferredSize(new Dimension(100, 400));
// 设置带自动换行的只读文本区域
jtx_output = new JTextArea();
// 不可编辑,只读文本
jtx_output.setEditable(false);
// jtx_input.setLineWrap(true);
JScrollPane sp1 = new JScrollPane(jtx_output);
sp1.setPreferredSize(new Dimension(300, 315));
jpL.add(sp1);
// 设置头像显示按钮
JButton jb = new JButton(new ImageIcon("管理员"));
jpR.add(jb);
// 设置可输入自动换行的文本区域
jtx_input = new JTextArea();
// jtx_input.setLineWrap(true);
JScrollPane sp2 = new JScrollPane(jtx_input);
sp2.setPreferredSize(new Dimension(300, 100));
jpL.add(sp2);
// 设置头像显示按钮
JButton jb1 = new JButton(new ImageIcon("images/头像.JPEG"));
jpR.add(jb1);
JButton Jb = new JButton("发送");
jf.add(jpL, BorderLayout.WEST);
jf.add(jpR, BorderLayout.EAST);
jf.add(Jb, BorderLayout.SOUTH);
jf.setVisible(true);
// 新建一个服务器套接字
try {
Socket ss = new Socket("127.0.0.1",8888);
input = ss.getInputStream();
output = ss.getOutputStream();
Jb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String out = jtx_input.getText()+"\n";
jtx_output.append("客户端说:"+out+"\n");
//将服务器段的消息发送给客户端
try {
byte[] bytes = out.getBytes("GBK");
output.write(bytes);
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
//接受服务器端发来的消息
while (true) {
String line = readLine(input);
jtx_output.append("服务器说 :"+line+"\n");
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 用来读取中文的方法
public String readLine(InputStream input) throws IOException {
// 字节输出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while (true) {
int n = input.read();
// 以换行符为读取的间隔
if (n == '\n')
break;
bos.write(n);
}
byte[] bytes = bos.toByteArray();
return new String(bytes, "GBK");
}
}
- 大小: 122.8 KB