一、网络编程的概念
网络编程主要是完成C/S程序的开发(client/server,客户端/服务器)。
C/S:开发两套程序,两套程序同时需要维护,例如QQ,一般比较稳定。
B/S(browser/server,浏览器/服务器):开发一套程序,客户端使用浏览器进行访问,一般稳定性和安全性较差。
二、网络编程TCP协议
TCP是一个可靠的协议,面向连接的协议,实现TCP协议,需要编写服务器和客户端,java.net包为实现网络应用程序提供类。
ServerSocket:此类实现服务器套接字。
Socket:此类实现客户端套接字。
Socket是网络驱动层提供给应用程序编程的接口和一种机制。
三、TCP实现Echo程序
Echo,意为应答,程序的功能是客户端向服务器发送一个字符串,服务器不做任何处理,直接把字符串返回给客户端,Echo程序是最为基本的客户/服务器程序。
//TCP先启动服务器端,再启动客户端。
//服务器端
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class EchoServer {
//实现echo程序
public static void main(String[] args) {
//创建一个服务器端的Socket(端口1024-65535)
try {
ServerSocket ss=new ServerSocket(6666);
System.out.println("服务器已启动,正在等待客户端的连接....");
//等待客户端的连接,造成阻塞,如果有客户端连接成功,就会立即返回一个Socket对象
Socket accept = ss.accept();
System.out.println("客户端连接成功!"+ss.getInetAddress().getHostAddress());
BufferedReader br =new BufferedReader
(new InputStreamReader(accept.getInputStream()));
//通过输入流来读取网络数据,如果没有数据会阻塞
String s = br.readLine();
System.out.println(s);
//获取输出流,向客户端返回消息
PrintStream ps=new PrintStream(new BufferedOutputStream(accept.getOutputStream()));
ps.println("echo:"+s);
ps.flush();
//关闭
ps.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//客户端
import java.io.*;
import java.net.Socket;
public class EchoClient {
public static void main(String[] args) {
//创建一个Socket对象,指定要连接的服务器
try {
Socket socket = new Socket("localhost",6666);
//获取socket的输入输出流
PrintStream ps=new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
ps.println("12345678");
ps.flush();
//读取服务器端返回的数据
String info=br.readLine();
System.out.println(info);
ps.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、服务器与多客户端通信
引入线程,用不同的线程对应不同的客户端。
//服务器端
import com.sun.corba.se.spi.activation.Server;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//主线程用于监听客户端的连接,每次有连接成功,开启一个线程来连接该客户端的消息
public class MultiServer {
//同时处理多个客户端
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
try {
ServerSocket ss=new ServerSocket(6666);
System.out.println("服务器已启动,正在等待连接...");
while (true){
Socket accept = ss.accept();
System.out.println(accept.getInetAddress().getHostAddress());
executorService.execute(new UserThread(accept));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//处理客户端请求的线程
class UserThread implements Runnable{
private Socket s;
public UserThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintStream ps=new PrintStream(new BufferedOutputStream(s.getOutputStream()));
String s = br.readLine();
System.out.println(s);
ps.println("echo:"+s);
ps.flush();
ps.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//客户端
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class MUltiClient {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
//创建一个Socket对象,指定要连接的服务器
try {
Socket socket = new Socket("localhost",6666);
//获取socket的输入输出流
PrintStream ps=new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("请输入:");
String s = scan.nextLine();
ps.println(s);
ps.flush();
//读取服务器端返回的数据
s=br.readLine();
System.out.println(s);
ps.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
五、多客户端之间的通信
通过服务器进行中转,发送一个数据包。
//服务器端
package communication;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {
public static void main(String[] args) {
//集合,保存客户端处理的线程
Vector<UserThread> vector=new Vector<>();
ExecutorService executorService = Executors.newFixedThreadPool(3);
//创建服务器端的Socket
try {
ServerSocket ss=new ServerSocket(6666);
System.out.println("服务器已启动,正在等待连接...");
while(true){
Socket accept = ss.accept();//接收
UserThread ut=new UserThread(accept,vector);
executorService.execute(ut);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//客户端处理的线程
class UserThread implements Runnable{
private String name;//客户端名称
private Socket s;
Vector<UserThread> vector;//客户端处理线程的集合
public ObjectInputStream ois;
private ObjectOutputStream oos;
private boolean flag=true;
public UserThread(Socket s, Vector<UserThread> vector) {
this.s=s;
this.vector=vector;
vector.add(this);
}
@Override
public void run() {
System.out.println("客户端"+s.getInetAddress().getHostAddress()+"已连接");
try {
ois=new ObjectInputStream(s.getInputStream());
oos=new ObjectOutputStream(s.getOutputStream());
while(flag){
//读取消息对象
Message m=(Message) ois.readObject();
int type=m.getType();
switch (type){
case MessageType.TYPE_SEND:
String to = m.getTo();
UserThread userThread;
int size = vector.size();
for (int i = 0; i < size; i++) {
userThread=vector.get(i);
if(to.equals(userThread.name)&&userThread!=this){
userThread.oos.writeObject(m);
break;
}
}
break;
case MessageType.TYPE_LOGIN:
name=m.getFrom();
m.setInfo("欢迎您");
oos.writeObject(m);
break;
}
}
oos.close();
ois.close();
} catch (IOException|ClassNotFoundException e) {
e.printStackTrace();
}
}
}
//客户端
package communication;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Client {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
ExecutorService executorService = Executors.newSingleThreadExecutor();
try {
Socket s=new Socket("localhost",6666);
System.out.println("服务器连接成功");
ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());
ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
//向服务器发送登录信息
System.out.println("请输入名称:");
String name = scanner.nextLine();
Message m=new Message(name,null,MessageType.TYPE_LOGIN,null);
oos.writeObject(m);
m=(Message) ois.readObject();
System.out.println(m.getInfo()+m.getFrom());
//启动读取消息的线程
executorService.execute(new ReadIndoRunnable(ois));
//使用主线程来发送消息
boolean flag=true;
while (flag){
m= new Message();
System.out.println("To:");
m.setTo(scanner.nextLine());
m.setFrom(name);
m.setType(MessageType.TYPE_SEND);
System.out.println("InFo:");
m.setInfo(scanner.nextLine());
oos.writeObject(m);
}
} catch (IOException|ClassNotFoundException e) {
e.printStackTrace();
}
}
}
//读取消息的线程
class ReadIndoRunnable implements Runnable{
private ObjectInputStream ois;
private boolean flag=true;
public ReadIndoRunnable(ObjectInputStream ois) {
this.ois = ois;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public void run() {
try {
while (flag) {
Message message = (Message) ois.readObject();
System.out.println("[" + message.getFrom() + "]" + "对我说 " + message.getInfo());
}
if(ois!=null){
ois.close();
}
}catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
//消息类型
package communication;
public class MessageType {
public static final int TYPE_LOGIN=0x1;//登录消息类型
public static final int TYPE_SEND=0x2;//发送消息类型
}
//消息
package communication;
import java.io.Serializable;
//消息包
public class Message implements Serializable {
private String from;//发送者
public String to;//接收者
private int type;//消息类型
private String info;//消息
@Override
public String toString() {
return "Message{" +
"from='" + from + '\'' +
", to='" + to + '\'' +
", type=" + type +
", info='" + info + '\'' +
'}';
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public Message(String from, String to, int type, String info) {
this.from = from;
this.to = to;
this.type = type;
this.info = info;
}
public Message() {
}
}
六、网络编程UDP协议
无连接,不可靠的协议。传输的数据报在64KB之内。
DatagramPacket:此类表示数据报包。
DatagramSocket:此类表示用来发送和接收数据报的套接字。
//UDP先运行客户端 等待传输数据,再运行服务器端 传输数据
//服务端
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class UDPServer {
public static void main(String[] args) {
String info="good good study,天天向上";
byte[] b=info.getBytes(StandardCharsets.UTF_8);
try {
//封装一个数据报包
DatagramPacket dp=new DatagramPacket(
b,
0,
b.length,
InetAddress.getByName("127.0.0.1"),
8000);
//本程序的端口
DatagramSocket ds=new DatagramSocket(9000);
ds.send(dp);
} catch (IOException e) {
e.printStackTrace();
}
}
}
//客户端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UDPClient {
public static void main(String[] args) {
byte[] b=new byte[1024];
DatagramPacket dp=new DatagramPacket(b,b.length);
try {
DatagramSocket ds=new DatagramSocket(8000);
System.out.println("正在接收数据中...");
ds.receive(dp);//接收数据
String s = new String(dp.getData(), 0, dp.getLength());
System.out.println(s);
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
七、URL
URL(统一资源定位符),是指向互联网“资源”的指针,抽象类URLConnection是所有类的超类,它代表应用程序和URL之间的通信链接。
网址就是一个URL。
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
public class URL {
public URL(String s) {
}
public static void main(String[] args) {
//互联网上每个文件都有一个唯一的URL
try {
URL u=new URL("https://blog.csdn.net/weixin_54068678?spm=1000.2115.3001.5343");
HttpURLConnection httpURLConnection = (HttpURLConnection) u.openConnection();
BufferedInputStream bi=new BufferedInputStream(httpURLConnection.getInputStream());
BufferedOutputStream bo=new BufferedOutputStream(new FileOutputStream("E:\\ideaWorkplace\\0401"));
byte[] b=new byte[1024];
int len=-1;
while((len=bi.read(b))!=-1){
bo.write(b,0,len);
bo.flush();
}
bi.close();
bo.close();
System.out.println("下载成功");
} catch (IOException e) {
e.printStackTrace();
}
}
private Object openConnection() {
return null;
}
}
八、MINA框架
一个简洁易用的基于TCP/IP通信的Java框架
下载地址:https://mina.apache.org/
开发一个MINA应用:创建连接,设定过滤规则,编写自己的消息处理器
具体参考其他网页。