Socket通信本质就是两个进程之间的通信。
为什么需要Socket进行网络通信?因为仅仅通过IP地址进行通信是不够的,同一台计算机同一时间会运行多个网络应用程序,例如浏览器、QQ、邮件客户端等。当操作系统接收到一个数据包的时候,如果只有IP地址,它没法判断应该发给哪个应用程序,所以,操作系统抽象出Socket接口,每个应用程序需要各自对应到不同的Socket,数据包才能根据Socket正确地发到对应的应用程序。
一个Socket就是由IP地址和端口号(范围是0~65535)组成,可以把Socket简单理解为IP地址加端口号。端口号总是由操作系统分配,它是一个0~65535之间的数字,其中,小于1024的端口属于特权端口,需要管理员权限,大于1024的端口可以由任意用户的应用程序打开。
java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。
服务器与客户端之间使用Socket通信的基本步骤如下:
TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送.以下是一些类提供的一套完整的有用的方法来实现 socket。
实例:
实现一个服务器与多个客户端的TCP通信。
MyServer.java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class MyServer implements Runnable {
private Socket client; //客户端的连接对象。
public MyServer(Socket client) {
this.client = client;
}
@Override
public void run() {
//输入流:负责获得客户端发来的消息。
BufferedReader input = null;
//输入流:负责从控制台获得用户输入的字符串。
BufferedReader in = null;
//输出流:负责给客户端发消息。(因为给屏幕输出,所以应该使用PrintStream)
PrintStream output = null;
boolean flag = true;
try {
//InputStreamReader字节流转换为字符流
input = new BufferedReader(new InputStreamReader(client.getInputStream()));
in = new BufferedReader(new InputStreamReader(System.in));
output = new PrintStream(client.getOutputStream());
while (flag) {
//获得客户端发来的字符串
String msg = input.readLine();
//这三种情况,都认为是结束线程
if (msg == null || "".equals(msg) || "bye".equals(msg)) {
flag = false;
} else {
System.out.println(msg);
//发送消息给客户端
System.out.println("请输入内容:");
msg = in.readLine();
if (msg == null || "".equals(msg) || "bye".equals(msg)) {
flag = false;
} else {
output.println("服务器:" + msg);
}
}
}
input.close();
output.close();
client.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
//创建一个ServerSocket.
boolean flag = true;
ServerSocket server = null;
try {
//启动服务
server = new ServerSocket(9999);
//接收客户端的请求,是阻塞方法
while (flag) {
System.out.println("服务器已经启动,等待客户端的请求....");
Socket client = server.accept();
//开启一个线程和客户端聊天
new Thread(new MyServer(client)).start(); //创建了一个服务器对象启动一个线程
}
System.out.println("服务器已经关闭....");
server.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
MyClient.java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
public class MyClient {
public static void main(String[] args) {
Socket client = null;
boolean flag = true;
//输入流:负责获得客户端发来的消息。
BufferedReader input = null;
//输入流:负责从控制台获得用户输入的字符串。
BufferedReader in = null;
//输出流:负责给客户端发消息。(因为给屏幕输出,所以应该使用PrintStream)
PrintStream output = null;
try {
//首先连接服务器
client = new Socket("localhost", 9999);
input = new BufferedReader(new InputStreamReader(client.getInputStream()));
in = new BufferedReader(new InputStreamReader(System.in));
output = new PrintStream(client.getOutputStream());
while (flag) {
//首先给服务发送消息
System.out.println("请输入内容:");
String msg = in.readLine();
if (msg == null || "".equals(msg) || "bye".equals(msg)) {
flag = false;
//最后这个'bye'必须发送给服务器
output.println(msg);
} else {
output.println("客户端:" + msg);
//获得服务发来的消息
msg = input.readLine();
if (msg == null || "".equals(msg) || "bye".equals(msg)) {
flag = false;
} else {
System.out.println(msg);
}
}
}
input.close();
in.close();
output.close();
client.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
先启动服务器,再启动两个客户端。 运行结果如下:
服务器控制台
服务器已经启动,等待客户端的请求....
服务器已经启动,等待客户端的请求....
服务器已经启动,等待客户端的请求....
客户端:你好,我是张三
请输入内容:
你好,我是服务器
客户端:你好,我是李四
请输入内容:
你好,我是服务器
客户端1
请输入内容:
你好,我是李四
服务器:你好,我是服务器
请输入内容:
bye
客户端2
请输入内容:
你好,我是张三
服务器:你好,我是服务器
请输入内容:
bye