Socket(JAVA)通信

最近学到了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方法,将之前的接受与发送消息的代码直接复制就行了)
具体代码如下:

服务器:
单线程:
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");
}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值