TCP通信:
Socket --相当于“虚拟链路两端的插座”。Socket负责完成通信。
ServerSocket --它只负责“接收”连接。它用于产生Socket。
服务器端编程:
1) 创建ServerSocket 对象,该对象负责“接收”连接。
2) 如果客户端有连接,ServerSocket 对象调用accept()方法返回一个Socket。
3) 通过IO流读取对方的信息,也可向对方发送数据。
客户端编程:
1) new Socket()来建立与远程服务器的连接。
2) 通过IO流读取对方的信息,也可向对方发送数据。
举列说明1(简单通信):
/**
* @author lhy
* @description 服务器端
*/
public class ServerTest {
public static void main(String[] args) {
PrintStream ps = null;
try {
// ServerSocket只负责“接收”连接,20000为端口号(标识该应用程序)
ServerSocket ss = new ServerSocket(20000);
System.out.println("服务器端等待连接...");
// 接收连接,它会阻塞线程
Socket socket = ss.accept();
// ----------------------下面统一面向IO编程--------------------------//
ps = new PrintStream(socket.getOutputStream());
ps.println("ServerTest你好");
} catch (IOException e) {
e.printStackTrace();
} finally {
ps.close();
}
}
}
/**
* @author lhy
* @description 客户端
*/
public class ClientTest {
public static void main(String[] args) {
BufferedReader br = null;
try {
Socket socket = new Socket("192.168.0.8", 20000);
// ----------------------下面统一面向IO编程--------------------------//
br = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
举列说明2(控制台多人聊天):
服务器端:
public class ServerTest {
static Set<Socket> clients = Collections
.synchronizedSet(new HashSet<Socket>());
public static void main(String[] args) {
ServerSocket ss = null;
try {
ss = new ServerSocket(20000);
System.out.println("服务器端等待连接...");
while (true) {
// 接收连接,它会阻塞线程
Socket socket = ss.accept();
clients.add(socket);
// 启动线程
new ServerThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 单独封装一个线程类
class ServerThread extends Thread {
private Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
while (true) {
// ----------------------下面统一面向IO编程--------------------------//
br = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
for (Socket s : ServerTest.clients) {
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println(line);// 输出各个客户端对应的Socket
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端:
public class ChatServer {
// 定义一个线程安全的Set集合
public static Set<Socket> clients = Collections
.synchronizedSet(new HashSet<Socket>());
public static void main(String[] args) throws IOException {
// ServerSocket只负责“接受”连接,不能通信
// 该服务器程序就在30002端口监听
ServerSocket ss = new ServerSocket(20000);
System.out.println("服务器等待连接...");
while (true) { // 这样保证每个客户端有一条线程
// 接受连接。它会阻塞线程
Socket socket = ss.accept();// 只要连接成功,它会返回socket
clients.add(socket);// 每次客户端连接进来,就将该客户端添加到clients集合中
System.out.println("当前用户数量:" + clients.size());
new ServerThread(socket).start();
}
}
}
class ServerThread extends Thread {
private Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
// -----原來读文件,现在改为读网络,只要改节点
try {
BufferedReader socketBr = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
String line = null;// line代表从网络中读取数据
while ((line = socketBr.readLine()) != null) {
for (Iterator<Socket> it = ChatServer.clients.iterator(); it
.hasNext();) {
Socket s = it.next();
try {
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println(line);// 输出到各客户端对应的socket
} catch (SocketException ex) {
it.remove();// 捕获到该socket的异常,即表明Socket已经断开
System.out.println("当前用户数量:" + ChatServer.clients.size());
// ex.printStackTrace();
}
}
}
} catch (SocketException se) {
ChatServer.clients.remove(socket);
System.out.println("当前用户数量:" + ChatServer.clients.size());
} catch (Exception e) {
e.printStackTrace();
}
}
}
小结:
System.in :读取键盘输入。包装方法:BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
socket.getInputStream():读取网络。包装方法:BufferedReadersocketBr = new BufferedReader(new InputStreamReader(socket.getInputStream()));
socket.getOutputStream():写入(输出到)网络。包装方法:PrintStream socketOut = new PrintStream(socket.getOutputStream());
System.out:输出到屏幕。
下面以之前IO讲的一张图来结束: