Java的网络概念,不是以主机来区分的,而是以进程来区分,JVM帮助解决网络传输,不需要我们考虑。
虽然JVM帮助用户隐藏网络原始信息,但是有一些操作还是留给用户来实现啦,网络的连接分为两种:TCP(可靠的数据连接)、UDP(不可靠的数据连接)
从网络编程的本质来讲也分为两种结构:
1、C/S结构(客户端、服务器):需要开发两种程序,一套服务器程序,一套客户端程序,如果要更新需要开发两套程序,开发复杂的高,但是安全、稳定、因为可以自定义协议、自定义传输端口;
2、B/S结构(浏览器/服务器):通过浏览器来访问服务器端程序,开发者只需要开发服务器端代码即可,只需要维护服务器一套程序,由于使用的是公共的协议。公开的端口,所以安全性较差。
服务器端代码:
public class HelloServer {
public static void main(String[] args) throws Exception {
//1、创建一个服务器对象,每一个服务器对象都必须要有一个监听端口
ServerSocket server=new ServerSocket(9999);//此时的服务在9999上,等待连接
System.out.println("等待客户连接............");
//2、需要等待客户连接,也就是说此时程序在此会进入到一个阻塞状态
Socket clietn=server.accept();//等待连接,连接的都是客户,每一个客户用Scoket表示
PrintWriter out=new PrintWriter(clietn.getOutputStream());
out.println("Hello World");
out.close();
server.close();
}
}
客户端代码:
import java.net.Socket;
import java.util.Scanner;
public class HelloClent {
@SuppressWarnings("resource")
public static void main(String[] args) throws Exception {
//表示连接的指定服务器端的主机名称和端口
Socket client=new Socket("localhost",9999);
Scanner sc=new Scanner(client.getInputStream());
sc.useDelimiter("\n");
while(sc.hasNext()){
System.out.println(sc.next());
}
client.close();
}
}
经典案例:Echo
利用多线程实现一个服务器多台主机
服务器端:
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class EchoServer {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(8888);
boolean flag=true;
while(flag){
Socket client = server.accept(); // 等待程序连接
new Thread(new MyThread(client)).start();;
}
server.close();
}
private static class MyThread implements Runnable {
private Socket client;
public MyThread(Socket client) {
super();
this.client = client;
}
@Override
public void run() {
try {
Scanner sc = new Scanner(client.getInputStream()); // 接收客户端数据
PrintStream out = new PrintStream(client.getOutputStream()); // 对客户端的回应信息
sc.useDelimiter("\n");// 以空格为分割符
boolean flag = true; // 作为循环标记
while (flag) { // 相当于一直循环
if (sc.hasNext()) {
String str = sc.next().trim();// 防止有多余空格出现
if ("byebye".equalsIgnoreCase(str)) { // 操作结束
out.println("BYEBYE!!!" + str); // 做出回应
flag = false; // 表示循环结束
break; // 退出循环
}
out.println("ECHO:" + str); // 做出回应
}
}
out.close();
sc.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
客户端
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class EchoClient {
public static void main(String[] args) throws Exception {
Socket cliten = new Socket("localhost", 8888);
Scanner keyScan = new Scanner(System.in); // 用户输入
keyScan.useDelimiter("\n");
Scanner netScan = new Scanner(cliten.getInputStream());
netScan.useDelimiter("\n");
PrintStream netOut = new PrintStream(cliten.getOutputStream());
boolean flag = true;
String str=null;
while (flag) {
System.out.print("请输入要发送的信息:");
if (keyScan.hasNext()) {
str = keyScan.next().trim();
netOut.println(str); //发送给服务器端
if(netScan.hasNext()){ //服务器有回应
System.out.println(netScan.next());
}
}if ("byebye".equals(str)) {
flag = false;
break;
}
}
cliten.close();
keyScan.close();
netScan.close();
}
}