首先明确一下,什么是网络编程?
网络编程就是使用套接字来达到进程之间通信的编程。
在java语言中,有三种套接字类,分别是:java.net.Socket;java.net.ServerSocket;java.net.DatagramSocket;
其中,Socket和ServerSocket是基于TCP协议的,DatagramSocket是基于UDP协议的。TCP和UDP的概念在这里不细说,具体的编程应用会在后续的博客中详细讲解。
本篇博客列举是一个最简单的基于TCP的套接字程序;
基于TCP的套接字,是客户端进程和服务器端进程进行通信,客户端向服务器端发送数据,服务器接收到数据后可以进行处理,可以再给客户端返回处理后的数据,给大家举个最简单的例子,我们通过游览器访问网页,此时游览器就是一个客户端,我们输入网址,客户端通过网址找到对应的远程HTTP服务器,向其发送请求,HTTP服务器接到客户端发来的请求后,给用户返回数据,在这里就是对应的网页,这就完成了一次基于TCP的套接字通信;由此例子也可以很容易理解,一个服务器进程通常可以与多个客户端进程相连接。
下面通过一个简单的例子来看一下如何实现套接字通信
我们需要写两个类,服务器类EchoServer和客户端类EchoClient
服务器通过监听端口,来接收客户端发来的连接请求,所以先创建一个Socket对象,并指定监听端口
ServerSocket server = new ServerSocket (8000); //要确保此端口不能被占用之后调用ServerSocket 的accept()方法,当接收到一个客户端发来的连接请求后,accept()方法返回一个Socket对象,这个Socket对象就与客户端的Socket对象之间形成了一条通信信道。
Socket socket = server.accept(); //等待客户端的连接
Socket类提供了getInputStream()方法和getOutputStream()方法,分别返回输入流和输出流对象,程序从输入流中读取数据,就可以获得从对方发来的数据;向输出流中写入数据,就可以向对方发送数据。这里写了两个方法, 用过滤流对从Socket对象获取的输入输出流进行包装。
private PrintWriter getWriter(Socket socket) throws IOException {接下来说一下客户端类:
OutputStream out = socket.getOutputStream();
return new PrintWriter(out, true);
}
private BufferedReader getReader(Socket socket) throws IOException {
InputStream in = socket.getInputStream();
return new BufferedReader(new InputStreamReader(in));
}
为了与服务器端进行通信,需要先创建一个Socket对象,参数port表示服务器所在的主机,这里的localhost表示客户和服务器端再同一个主机上,
String host = "localhost";
int port = 8000;
Socket socket = new Socket(host, port);
客户端中从键盘输入数据写到输出流中,并从输入流中获取从服务器返回的数据。
以下为服务器EchoServer和客户端EchoClient的全部代码:EchoServer:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class EchoServer {
private int port = 8000;
private ServerSocket serverSocket;
public EchoServer() throws IOException {
serverSocket = new ServerSocket(port);
System.out.println("服务器启动");
}
public String echo(String msg) {
return "服务器传回的数据:" + msg;
}
private PrintWriter getWriter(Socket socket) throws IOException {
OutputStream out = socket.getOutputStream();
return new PrintWriter(out, true);
}
private BufferedReader getReader(Socket socket) throws IOException {
InputStream in = socket.getInputStream();
return new BufferedReader(new InputStreamReader(in));
}
public void service() {
while (true) {
Socket socket = null;
try {
socket = serverSocket.accept();
System.out.println("新的连接以建立");
System.out.println("客户端IP" + socket.getInetAddress());
System.out.println("客户端端口号" + socket.getPort());
BufferedReader br = getReader(socket);
PrintWriter pw = getWriter(socket);
String msg = null;
while ((msg = br.readLine()) != null) {
System.out.println("客户端传来的数据:" + msg);
pw.println(echo(msg));
if (msg.equals("bye")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) throws IOException {
new EchoServer().service();
}
EchoClient:
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class EchoClient {
private String host = "localhost";
private int port = 8000;
private Socket socket;
public EchoClient() throws IOException {
socket = new Socket(host, port);
}
private PrintWriter getWriter(Socket socket) throws IOException {
OutputStream out = socket.getOutputStream();
return new PrintWriter(out, true);
}
private BufferedReader getReader(Socket socket) throws IOException {
InputStream in = socket.getInputStream();
return new BufferedReader(new InputStreamReader(in));
}
public void talk() throws IOException {
try {
BufferedReader br = getReader(socket);
PrintWriter pw = getWriter(socket);
Scanner sc = new Scanner(System.in);
String msg = null;
while ((msg = sc.next()) != null) {
pw.println(msg);
System.out.println(br.readLine());
if (msg.equals("bye")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws IOException {
new EchoClient().talk();
}
运行两个类的main()方法,就建立了通信,当客户端输入bye时,跳出while循环,执行后边的socket.close()断开连接,服务器收到bye后,也关闭自己的socket对象和ServerSocket对象,结束本次通信。下图为运行结果:
以下两篇博客详解Socket和ServerSocket两个类