1.1Socket编程的一般步骤
使用Socket进行通讯的一般连接过程:服务端监听某个端口是否有连接请求,客服端想服务端发出连接请求,服务端向客户端发回接收消息这样就建立一个连接。服务端和客户端都可以通过发送、写入等方法与对方通信。
Socket工作过程包含以下四个基本的步骤:
- 创建Socket
- 打开连接到Socket的输入/输出流
- 按照一定的协议对Socket进行读/写操作
- 关闭Socket
客服端与服务器端的通讯步骤
1.2 Socket服务端编程
在服务器端程序编程中,第一步是监听端口,也就是监听是否有客服端连接到达。实现服务器端监听的代码如下:
ServerSocket ss = new ServerSocket (int port);
服务器端编程的第二步是获得连接。实现获得连接的代码:
Socket socket = ss.acept();
最后,在服务器端通信完成以后,关闭服务器端连接:
Socket服务器端编程示例:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) {
ServerSocket ss = null;//服务器端
Socket s = null;//客服端
InputStream in = null;//输入流
OutputStream out = null;//输出流
//没有下面的对输入流和输出流进行包装,只能输入一个字符,就会马上从服务器端返回数据
BufferedReader reader = null;//缓冲流
PrintStream print=null;//输出流
try {
//服务端建立连接,端口号为10000
ss= new ServerSocket(10000);
//服务器端接受客户端的请求
s=ss.accept();
//从客户端获取输入流,用于读取用户端数据
in=s.getInputStream();
//想客服端写东西
out=s.getOutputStream();
reader=new BufferedReader(new InputStreamReader(in));
print = new PrintStream(out);
/*//这是只能输入一个字符,就会马上从服务器端返回数据的代码,没有经过输入流和输出流包装
byte[] b = new byte[1024];
int len = in.read(b);
String clientStr = new String(b, 0, len);
String outputStr=clientStr+",您好!";
out.write(outputStr.getBytes());*/
String clientStr;
//使用循环,解决每当客服端程序输入一句话按返回键后服务端就结束的问题
while (!(clientStr = reader.readLine()).equalsIgnoreCase("exit")) {
String outputStr = clientStr+"您好!";
print.println(outputStr);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
out.close();
in.close();
s.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
服务器端启动以后,可以使用Windows自带的telnet命令,检测写的服务器端程序是否正常。在命令行输入telnet localhost 10000,localhost是指本机,127.0.0.1也是代表本地。
上面程序还有一个致命问题,只能启动一个客服端,只实现了一个客服端的通讯。修改代码如下:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class Server2 {
private List<Socket> sockets = new ArrayList<Socket>();
public static void main(String[] args) {
new Server2().startServer();
}
public void startServer() {
ServerSocket ss = null;// 服务器端
try {
// 服务端建立连接,端口号为10000
ss = new ServerSocket(10000);
while (true) {
// 服务器端接受客户端的请求
Socket s = ss.accept();// ServerSocket.accept此方法在连接接入之前一直阻塞。
sockets.add(s);
// 启动一个线程
new Start(s).start();
// new Server2().new Start(s).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class Start extends Thread {
Socket s = null;// 客服端
InputStream in = null;// 输入流
// 没有下面的对输入流和输出流进行包装,只能输入一个字符,就会马上从服务器端返回数据
BufferedReader reader = null;// 缓冲流
public Start(Socket _socket) {
this.s = _socket;
}
@Override
public void run() {
try {
// 从客户端获取输入流,用于读取用户端数据
in = s.getInputStream();
// 想客服端写东西
reader = new BufferedReader(new InputStreamReader(in));
// 使用循环,解决每当客服端程序输入一句话按返回键后服务端就结束的问题
// 客户端可以不断的输入,知道接收到exit服务器不在回复
out: while (true) {
String clientStr = reader.readLine();
String outputStr = clientStr + "您好!";
for (Socket socket : sockets) {
if (clientStr.equalsIgnoreCase("exit")) {
System.out.println(sockets.size() + "——eee——" + s
+ "次用户已被删除");
sockets.remove(s);
break out;
}
System.out
.println(sockets.size() + "--------" + socket);
OutputStream out = socket.getOutputStream();// 输出流
PrintStream print = new PrintStream(out);// 输出流
print.println(outputStr);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}