网络编程
一.Socket和ServerSocket类
1.用来实现双向安全连接网络
2.ServerSocket创建一个服务器Scoket,定义一个端口号,然后用Socket定义一个客户端并定义其链接的IP地址和端口号
3.服务器和客户端内容相互传输服务端实现代码:
package com.qfedu.test1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务端
* @author WHD
*
*/
public class Server {
public static void main(String[] args) {
// 通过ServerSocket 创建一个服务器Socket
// 端口号 表示每一个应用程序唯一的编号
// 一些应用程序有默认的端口号 比如 tomcat 8080 mysql 3306
// 端口号取值范围 0~ 65535 我们在定义端口号的时候 9000以上都可以使用
try {
ServerSocket ss = new ServerSocket(8899);
System.out.println("服务器启动完毕,等待连接。。。。。");
Socket socket = ss.accept(); // 此时调用accept方法 程序将会阻塞 等待客户端连接
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info = br.readLine();
System.out.println("客户端发送的信息是:" + info);
//传输客户端代码实现
OutputStream os = socket.getOutputStream();
os.write("睡了".getBytes());
socket.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.qfedu.test1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
/**
* 客户端
* TCP Transmission Control Protocol
* 面向连接的 可靠 安全的 传输协议
* TCP连接和断开涉及到 三次握手 四次挥手
* 软件的分类
* B/S Browser Server 基于浏览器的软件 代码编写相对简单 因为我们只需要编写一套代码 发布与服务器就可以
* C/S Client Server 基于客户端的软件 代码相对复杂 因为我们要两套程序 一个客户端 一个服务器 维护难度
* @author WHD
*
*/
public class Client {
public static void main(String[] args) {
try {
// 地址就写当前电脑的ip地址
// 本机的ip地址 localhost 等价 127.0.0.1
Socket socket = new Socket("localhost", 8899);
System.out.println("客户端准备就绪。。。。。。");
OutputStream os = socket.getOutputStream();
os.write("服务器你好,睡了吗?".getBytes());
socket.shutdownOutput(); // 关闭写入 输出流
//接收服务器内容传入
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
System.out.println("好激动,服务器回话了" + br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务器代码解释:
先用ServerSocket创建一个服务器端口号对象ss,然后用ss调用accept,程序阻塞,等待客户端信息传入,用ss.accept定义的socket调用getInputStream接受客户端写入的信息,并创建对象is然后用BufferedReader进行字节流缓冲,且需要传入new InputStreamReader(is),此代码含义为将getInputStream定义的is对象当参数传入InputStreamReader中,然后再将其创建的对象当作参数传入BufferedReader中,创建一个字符缓冲流对象,然后用此对象调用readLine()方法,将接受到的消息读取后传入info中转化为字符串进行输出。
用accept定义的socket调用getOutputStream()方法将客户端的话进行传输,用其创建的对象,调用write进行传入信息的进行传入,其中传入的信息需要调用getBytes()进行转化,然后用shutdownOutput()方法进行写入结束的声明。
客户端代码:
package com.qfedu.test1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
/**
* 客户端
* TCP Transmission Control Protocol
* 面向连接的 可靠 安全的 传输协议
* TCP连接和断开涉及到 三次握手 四次挥手
* 软件的分类
* B/S Browser Server 基于浏览器的软件 代码编写相对简单 因为我们只需要编写一套代码 发布与服务器就可以
* C/S Client Server 基于客户端的软件 代码相对复杂 因为我们要两套程序 一个客户端 一个服务器 维护难度
* @author WHD
*
*/
public class Client {
public static void main(String[] args) {
try {
// 地址就写当前电脑的ip地址
// 本机的ip地址 localhost 等价 127.0.0.1
Socket socket = new Socket("localhost", 8899);
System.out.println("客户端准备就绪。。。。。。");
OutputStream os = socket.getOutputStream();
os.write("服务器你好,睡了吗?".getBytes());
socket.shutdownOutput(); // 关闭写入 输出流
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
System.out.println("好激动,服务器回话了" + br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码解释:
用Socket进行和服务器进行连接,然后用getOutputStream进行数据的传输,其定义的对象进行信息的输入,shutdownOutput进行写入结束生命
getInputStream对服务器端传入数据进行读取,BufferedReader方法进行缓冲,具体解释看服务器,然后再输出语句中用缓冲对象调用readLine进行信息输出。
4.客户端对服务器进行对象的传输,定义的对象类记得序列化,不然不能进行字节流的传输,服务器具体代码实现:
package com.qfedu.test2;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
ublic class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8899);
System.out.println("服务器启动完毕……");
Socket socket = ss.accept();
InputStream is = socket.getInputStream();//接收返回的数据
ObjectInputStream ois = new ObjectInputStream(is);
Student stu = (Student) ois.readObject();
System.out.println(stu);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
代码解释:
还是先用ServerSocket定义端口号,然后accept进行阻断,getInputStream接受客户端传入的数据,然后用ObjectInputStream进行信息转化,用气定义的对象调用readObject方法进行数据的读取并转化为我们将要输出的对象类,然后用输出语句直接输出。
客户端代码:
package com.qfedu.test2;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* 客户端
* 向服务器发送一个对象
* @author WHD
*
*/
public class Client {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 8899);
System.out.println("客户端开始发送数据……");
OutputStream os = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(new Student("赵四", 20));
socket.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码解释:
先用Socket连接服务器,getOutputStream对服务器进行信息输出,ObjectOutputStream将即将传入的信息进行转化,并存入getOutputStream定义的类中writeObject进行信息的写入,在writeObject中直接定义对象,shutdownOutput生命结束写入。
5.多个客户端一个服务器利用线程进行信息的相互传入服务器端代码如下:
package com.qfedu.test3;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务器
* 因为目前是三个客户端来访问 所以我们要
* 1.服务器必须一值处于开启状态
* 2.可以使用多个线程来分别回应客户端
* @author WHD
*
*/
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8899);
System.out.println("服务器启动……");
while(true) {
Socket socket = ss.accept(); // 不同的客户端请求访问 返回的是不同的socket
// 执行完以上代码 程序继续 服务器将停止 所以我们编写一个线程类 代替服务器应答
new ServerThread(socket).start();;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码解释:
ServerSocket创建端口号,然后accept进行阻塞,new ServerThread(socket).start();定义线程类调用线程,socket值不同代表不同的调用线程,其中while循环保证服务器一直处于激活状态
线程代码具体如下:
package com.qfedu.test3;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
/**
* 当前了你作为服务器应答的线程类
* 如何区分不同的请求?
* 通过Socket 本类中声明一个属性 Socket
* 这个Socket将作为run方法中回应客户端的重要依据
* @author WHD
*
*/
public class ServerThread extends Thread{
private Socket socket;
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
public ServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = this.socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
while(( line =br.readLine()) != null) {
System.out.println("客户端说的话: " + line);
}
OutputStream os = socket.getOutputStream();
os.write("客户端你好,睡了".getBytes());
socket.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码解释如下:
先创建一个socket类,接收服务器传入的不同线程类信息,this.socket.getInputStream();接收不同线程传入的不同信息,BufferedReader进行缓冲,并转化,定义一个line,用br.readLine()进行信息的遍历,并传入到line中,进行输出
信息输出时getOutputStream对客服端进行信息输出,os.write进行信息写入,getBytes()进行信息转化,socket.shutdownOutput()进行信息停止写入标识。
客户端代码如下:
package com.qfedu.test3;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
/**
* 模拟多个客户端访问服务器 服务器 一一回应
* @author WHD
*
*/
public class Client3 {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 8899);
OutputStream os = socket.getOutputStream();
os.write("服务器你好,我是3号客户端".getBytes());
socket.shutdownOutput();
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
while(( line =br.readLine()) != null) {
System.out.println("服务器回话了:" + line);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
// 关闭资源
}
}
}
代码解释:
Socket连接客户端,getOutputStream()进行信息传入客户端,write信息写入,getBytes信息转化,shutdownOutput信息停止写入
getInputStream服务器传回信息读取,BufferedReader缓冲读取,定义字符串类line,br.readLine()信息的遍历,并传入line进行输出
二.DatagramSocket和DatagramPacket类:
服务器端代码:
package com.qfedu.test5;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.net.SocketException;
/**
* 服务器
* @author WHD
*
*/
public class Server {
public static void main(String[] args) {
try {
DatagramSocket ds = new DatagramSocket(8899);
System.out.println("服务器启动……");
byte [] bag = new byte[1024];
// 1 接收内容用的byte数组 --- 准备装快递包裹
// 2 数组的长度 --- 包裹大小
DatagramPacket dp = new DatagramPacket(bag, bag.length);
ds.receive(dp); // 接收包裹
// 拆快递的过程
System.out.println(new String(dp.getData(),0,dp.getData().length));
String returnInfo = "客户端hello";
byte [] returnBag = returnInfo.getBytes();
SocketAddress socketAddress = dp.getSocketAddress();
// 第三个参数是SocketAddress 相当于回话给对方的地址 可以直接从已经接受过的包裹直接获取
DatagramPacket dp1 = new DatagramPacket(returnBag, returnBag.length, socketAddress);
ds.send(dp1);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
DatagramSocket创建端口号,定义一个接收数组bag,并定义其长度,DatagramPacket用数组接收服务器传入的数据,用ds.receive(dp)进行读取遍历,System.out.println(new String(dp.getData(),0,dp.getData().length));输出数组,括号内的参数为接收自那个数组,偏移量,数组长度
将要传给客户端的信息封存到String修饰的对象中,用数组进行接收,获取客户端的端口信息,DatagramPacket对数组进行转化,ds.send(dp1);发送给客户端。
客户端代码:
package com.qfedu.test5;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
/**
* UDP 用户数据报协议 报文 数据包
* 非面向连接 不安全 不可靠 效率高
* @author WHD
*
*/
public class Client {
public static void main(String[] args) {
String info = "hello 服务器";
System.out.println("客户端准备发送信息……");
byte [] datas = info.getBytes();
InetAddress localHost;
try {
localHost = InetAddress.getLocalHost();
// 1 发送的内容 ---包裹内容
// 2 内容大小 --- 包裹的重量
// 3 地址 --- 地址
// 4 端口号 --- 联系方式
DatagramPacket dp = new DatagramPacket(datas, datas.length, localHost, 8899);
// 创建DatagramSocket 对象用于发送数据
DatagramSocket ds = new DatagramSocket();
ds.send(dp); // 通过send方法将打包好的内容发送
byte [] saveBag = new byte[1024];
DatagramPacket dp1 = new DatagramPacket(saveBag, saveBag.length);
ds.receive(dp1);// 接收到包裹
//拆快递
System.out.println("服务器回话了:" + new String(dp1.getData(),0,dp1.getData().length));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码解释:
将要传给服务器的信息存进String修饰的对象info中,将其转化为字符串存入数组中,定义端口号,getLocalHost获取本机端口号,并传给我们定义的端口号DatagramPacket读取数组信息,并连接服务器,DatagramSocket将DatagramPacket读取的信息进行转化,ds.send(dp);发送给客户端
定义一个数组和长度用于接收服务器传入的信息,DatagramPacket接收服务器传入的信息,并存进数组,ds.receive(dp1);对读取到的信息进行遍历,输出读取的那个数组,偏移量,和数组长度。