这2天,看了看网路编程,这里记录一下自己的理解。
网络编程,简单的理解,就是通讯,这里说服务器和客户端的通讯。服务器一直监听着,看是不是有客户来访问。
服务器:相当于一个家,或者一个定点买东西的地方,肯定是需要地址的,不然别人找不到地方对吧。
JAVA 体面提供了InetAddress 对象,通过getByName 等方法,可以获取地址(住址名称)的。
客户端:客户嘛,大家都明白,就是要去和服务器进行回话,相当于我要和你联系,需要你家住址(起码要电话号码之类的,才能找到你)。
地址和端口:地址就不说了,就是能确定你位置一个东东。因为一台服务器,可能有很多服务,这里需要用端口来区分。好比:我到你家买东西,8080 这个端口卖饼干,8081 端口可以卖水果等等。
交互:我作为客户,想到你家买东西,那么我肯定要知道你家地址,我只买饼干,那么我还要知道你家饼干的端口8080.你作为服务器,也就是卖住,你不知道什么人来买,因此你只需要将卖饼干 和买水果的端口打开,派人看着(监听)就行。
JAVA 给我们节省了很多,对于服务器,只需要用ServerSocket 监听端口,有人访问之后有accept()进行允许就行了。对于客户,要用Socket 传入地址(Address) 和端口(PORT)知道你 去哪,买什么。
当然,两边都有了, 当我有地址 有 端口,对你进行访问的时候,肯定得有通道吧,以前可以走路 坐车。现在起码也要卫星信号,才能电话连接对吧。JAVA 这里用了InputStream 和OutputStream ,可以用(Reader 和Writer),通过getInputStream (),getOutputStream ().获得,这就是双方的一个联系通道。
下面我来看看一个简单的程序:
Server 服务器端:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class MyServer {
public static final int PORT = 8080;
public static void main(String[] args) throws IOException, InterruptedException {
// 服务器现监听一个端口
ServerSocket ss = new ServerSocket(PORT);
// 如果同一人访问,就给他开门
Socket s = ss.accept();
try{
// 获取双方的传输通道
BufferedReader in = new BufferedReader(
new InputStreamReader(
s.getInputStream()));
// 这里注意 有个true,表示自动刷新缓冲区
// 如果没有这个,他们就会一直等待信息,没有一行信息就无法进行下面的操作,一直会等到缓冲区满
// 因此用刷新功能,将信息通过网络发送出去,客户端那边一样,信息需要通过网络交互
PrintWriter out = new PrintWriter(
new OutputStreamWriter(
s.getOutputStream()),true);
while(true){
// 获取客户端来的消息,"END" 就退出
String str = in.readLine();
if("END".equals(str)){
break;
}
System.out.println("str is :"+str);
out.println(str);
Thread.currentThread().sleep(1000);
}
}finally{
// 这里为了节省资源,都关闭
s.close();
ss.close();
}
}
}
Client 客户端:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
public class MyClient {
public static void main(String[] args) throws IOException {
// 地址,null 表示本地127.0.0.1
InetAddress addr = InetAddress.getByName(null);
// 需要的端口
Socket socket = new Socket(addr, 8080);
try {
System.out.println("socket = " + socket);
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
// 自动刷新
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),true);
// 我假设 说十句话
for (int i = 0; i < 10; i++) {
out.println("hello :" + i);
String str = in.readLine();
System.out.println(str);
}
out.println("END");
} finally {
socket.close();
}
}
}
那么同理,我们只需修改一点,就可以完成多个客户端的访问,当然不是并发,这里用了点线程
服务器端线程
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
public class ServerThread extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
// 服务器端的构造器,需要套接字socket
public ServerThread(Socket s) throws IOException {
socket = s;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),
true);
// 启动run
start();
}
public void run() {
String str;
try {
while (true) {
str = in.readLine();
if ("END".equals(str)) {
break;
}
System.out.println("Str is :" + str);
out.println(str);
}
System.out.println("closing...");
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端线程
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
public class ClientThread extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private static int counter = 0;
private int id = counter++;
private static int threadcount = 0;
public static int getThreadCount() {
return threadcount;
}
// 客户端的构造,需要地址
public ClientThread(InetAddress addr) {
System.out.println("client is :" + id);
threadcount++;
try {
socket = new Socket(addr, 8080);
} catch (IOException e) {
e.printStackTrace();
}
try {
in = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
out = new PrintWriter(new OutputStreamWriter(socket
.getOutputStream()), true);
start();
} catch (IOException e) {
try {
socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
public void run() {
try {
for (int i = 0; i < 10; i++) {
out.println("cliend is :" + id + ":" + i);
String str;
try {
str = in.readLine();
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
}
}
out.println("END");
} finally {
try {
socket.close();
} catch (IOException e) {
threadcount--;
}
}
}
}
服务器监听,并创建新的
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class MultiServer {
static final int PORT = 8080;
public static void main(String[] args) throws IOException {
ServerSocket s = new ServerSocket(PORT);
System.out.println("Server Started");
try {
while (true) {
Socket socket = s.accept();
try{
// 每一个访问该端口的,都从新一个线程
new ServerThread(socket);
}catch (IOException e) {
socket.close();
}
}
} finally{
s.close();
}
}
}
模拟多个客户端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
public class ClientThread extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private static int counter = 0;
private int id = counter++;
private static int threadcount = 0;
public static int getThreadCount() {
return threadcount;
}
// 客户端的构造,需要地址
public ClientThread(InetAddress addr) {
System.out.println("client is :" + id);
threadcount++;
try {
socket = new Socket(addr, 8080);
} catch (IOException e) {
e.printStackTrace();
}
try {
in = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
out = new PrintWriter(new OutputStreamWriter(socket
.getOutputStream()), true);
start();
} catch (IOException e) {
try {
socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
public void run() {
try {
for (int i = 0; i < 10; i++) {
out.println("cliend is :" + id + ":" + i);
String str;
try {
str = in.readLine();
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
}
}
out.println("END");
} finally {
try {
socket.close();
} catch (IOException e) {
threadcount--;
}
}
}
}
小结:从代码上看,其实很简单,以前假设 我是到你家,8080端口去买东西 ,聊天什么的。现在有很多人去你家,同一个端口做事。因此每一个人都创建一个单独的线程,隔离出来就行了。