1、Socket简介
1.1、什么是Socket
1)通信链路的端点就被称为“套接字”(英文名Socket)
2)是提供给应用程序的接口
3)Socket的底层机制复杂,Java平台提供了一些简单的API,可以更简单有效的使用Socket开发而无需了解底层机制
1.2、基于TCP协议的Socket编程
1)基于TCP协议的Socket网络通信
用来实现双向安全连接网络通信
2)Socket通信模型
进行网络通信时,Socket需要借助数据流来完成数据的传递工作
3)Socket网络编程一般可以分成如下步骤进行
1.3、Socket中实现对象的传递
1)传递对象信息
ObjectOutputStream oos = new ObjectOutputStream(…);
oos.writeObject(…);
ObjectInputStream ois = new ObjectInputStream(…);
Object = ois.readObject();
1.4、基于UDP协议的Socket编程
1)
2)基于UDP协议的Socket网络编程步骤
2、模拟用户登录的功能
需求说明
模拟用户登录的功能
实现客户发送登录用户信息,服务器端显示登录信并响应给客户端登录成功
1)客户端实现步骤如下:
(1)建立连接,连接指向服务器及端口
(2)打开Socket关联的输入/输出流
(3)向输出流中写入信息
(4)从输入流中读取响应信息
(5)关闭所有的数据流和Socket
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class LoginClient {
/*
* 示例01:模拟用户登录的功能,实现客户端发送用户登录信息,服务器端显示登录信息并响应给客户端登录成功
*
* 客户端实现步骤如下:
* (1)建立连接,连接指向服务器及端口
* (2)打开Socket关联的输入/输出流
* (3)向输出流中写入信息
* (4)从输入流中读取响应信息
* (5)关闭所有的数据流和Socket
*/
public static void main(String[] args) {
Socket socket=null;
OutputStream os=null;
InputStream is=null;
BufferedReader br=null;
try {
//建立客户端Socket连接,指定服务器的位置为本机以及端口为8800
socket=new Socket("localhost",8800);
//打开输出流
os=socket.getOutputStream();
//接收服务器端的响应,即从输入流中读取信息
String info="用户名:Tom;用户密码:123456";
/*
byte[] byte=info.getBytes();
os.write(byte);
*/
os.write(info.getBytes());
//关闭通道
socket.shutdownOutput();
//接收服务器端的响应,即从输入流中读取信息
String reply;
is=socket.getInputStream();
br=new BufferedReader(new InputStreamReader(is));
while((reply=br.readLine())!=null){
System.out.println("我是客户端,服务器的响应为:"+reply);
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
br.close();
is.close();
os.close();
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
2)服务器端实现步骤如下:
(1)建立连接,监听端口
(2)使用accept()方法等待客户端发起通信
(3)打开Socket关联的输入/输出流
(4)向输出流中写入信息
(5)从输入流中读取响应信息
(6)关闭所有的数据流和Socket
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class LoginServer {
public static void main(String[] args) {
/*
* 示例01:模拟用户登录的功能,实现客户端发送用户登录信息,服务器端显示登录信息并响应给客户端登录成功
*
* 服务器端实现步骤如下:
* (1)建立连接,监听端口
* (2)使用accept()方法等待客户端发起通信
* (3)打开Socket关联的输入/输出流
* (4)向输出流中写入信息
* (5)从输入流中读取响应信息
* (6)关闭所有的数据流和Socket
*/
ServerSocket serverSocket=null;
Socket socket=null;
InputStream is =null;
BufferedReader br =null;
OutputStream os=null;
try {
//建立一个服务器Socket(ServerSocket),指定端口8800并开始监听
serverSocket=new ServerSocket(8800);
//使用accept()方法等待客户端发起通信
socket=serverSocket.accept();
//打开输入流
is=socket.getInputStream();
//获取客户端信息,即从输入流读取信息
br=new BufferedReader(new InputStreamReader(is));
String info;
while((info=br.readLine())!=null){
System.out.println("我是服务器,客户登录信息为:"+info);
//给客户端一个响应,即向输出流中写入信息
}
os=socket.getOutputStream();
String reply="欢迎你,登录成功";
os.write(reply.getBytes());
/*
byte[] byte=reply.getBytes();
os.write(byte);
*/
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
//关闭资源
try {
os.close();
br.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
3、多客户端用户登录
需求说明
升级前一个上机内容,实现多客户端用户登录
分析
创建服务器端线程类,run()方法中实现对一个请求的响应处理
修改服务器端代码,实现循环监听状态
服务器端每监听到一个请求,创建一个处理线程
1)Student类
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private int age;
public Student() {
super();
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
2)ServerThread类
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.net.Socket;
public class ServerThread extends Thread {
//声明一个Socket类型的属性
private Socket socket;
public ServerThread(Socket socket) {
super();
this.socket = socket;
}
@Override
public void run() {
InputStream is =null;
ObjectInputStream ois =null;
OutputStream os =null;
try {
//通过返回的Socket对象调用方法获取一个输入流来读取客户端发送过来的消息
is =socket.getInputStream();
ois = new ObjectInputStream(is);
Object object = ois.readObject();
Student student = (Student)object;
System.out.println("我这边是服务器:客户端发送给我的数据是:"+student.getName()+","+student.getAge());
socket.shutdownInput();
//服务器接收客户端消息后,需要给客户端一个响应信息
os =socket.getOutputStream();
String result = "获取的对象姓名和年龄正确";
byte[] bytes = result.getBytes();
os.write(bytes);
System.out.println("给客户端的响应信息发送成功");
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
try {
os.close();
ois.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3)Server类
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
/*
* 多个客户端向服务器发送请求,服务器怎么办???
*
*
* 客户端跟之前客户端做的事情没有任何改变
* 客户端通过输出流发送请求信息
* 客户端通过输入流获取服务器端的响应信息
* 服务器端做的事情跟之前服务器端做的事情不一样
* 服务器端循环去侦听客户端的请求,侦听到一个请求就会获取一个Socket类对象,将这个Socket类对象作为参数传递给服务器线程类的有参构造方法里去
* 服务器线程类通过获取到的Socket类对象去执行原来服务器所做的事情
* 通过输入流获取客户端的请求信息
* 通过输出流发送响应信息给客户端
*
*/
public static void main(String[] args) {
//创建ServerSocket类对象
ServerSocket ss =null;
Socket socket =null;
try {
ss = new ServerSocket(10088);
while(true){
socket =ss.accept();
//将获取到的socket对象传递到线程类中
ServerThread st = new ServerThread(socket);
st.start();
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4)Client1类
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client1 {
public static void main(String[] args) {
//创建通信链路的端点客户端套接字
Socket socket = null;
OutputStream os = null;
ObjectOutputStream oos =null;
InputStream is =null;
BufferedReader br =null;
try {
socket = new Socket("127.0.0.1", 10088);
//获取输出流将数据发送出去
os =socket.getOutputStream();
//准备Student类对象
Student stu = new Student("张三",19);
oos = new ObjectOutputStream(os);
oos.writeObject(stu);
System.out.println("我是客户端,我将数据发送完毕");
//关闭通道
socket.shutdownOutput();
//客户端需要通过输入流读取服务器端发送过来的消息
is =socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
String result =br.readLine();
System.out.println("我是客户端,接收到的服务器端响应信息为:"+result);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
br.close();
is.close();
oos.close();
os.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5)Client2类
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client2 {
public static void main(String[] args) {
//创建通信链路的端点客户端套接字
Socket socket = null;//创建一个未连接的套接字
OutputStream os = null;
ObjectOutputStream oos =null;
InputStream is =null;
BufferedReader br =null;
try {
socket = new Socket("127.0.0.1", 10088);
//获取输出流将数据发送出去
os =socket.getOutputStream();
//准备Student类对象
Student stu = new Student("李四",22);
oos = new ObjectOutputStream(os);
oos.writeObject(stu);
System.out.println("我是客户端,我将数据发送完毕");
//关闭通道
socket.shutdownOutput();
//客户端需要通过输入流读取服务器端发送过来的消息
is =socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
String result =br.readLine();
System.out.println("我是客户端,接收到的服务器端响应信息为:"+result);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
br.close();
is.close();
oos.close();
os.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
6)Client3类
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client3 {
public static void main(String[] args) {
//创建通信链路的端点客户端套接字
Socket socket = null;
OutputStream os = null;
ObjectOutputStream oos =null;
InputStream is =null;
BufferedReader br =null;
try {
socket = new Socket("127.0.0.1", 10088);
//获取输出流将数据发送出去
os =socket.getOutputStream();
//准备Student类对象
Student stu = new Student("如花",16);
oos = new ObjectOutputStream(os);
oos.writeObject(stu);
System.out.println("我是客户端,我将数据发送完毕");
//关闭通道
socket.shutdownOutput();
//客户端需要通过输入流读取服务器端发送过来的消息
is =socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
String result =br.readLine();
System.out.println("我是客户端,接收到的服务器端响应信息为:"+result);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
br.close();
is.close();
oos.close();
os.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4、客户咨询问题
需求说明
实现客户咨询问题,客服人员答复问题
分析
咨询时,客户是发送方,客服人员是接收方
答复时,客服人员是发送方,客户是接收方,实现思路和咨询时相同
1)LoginServer类
import java.io.IOException;
import java.net.*;
public class LoginClient {
public static void main(String[] args) {
String info="您好,我想咨询一些问题!";
byte[] infos=info.getBytes();
DatagramSocket socket=null;
try {
InetAddress ia=InetAddress.getByName("localhost");
DatagramPacket dp = new DatagramPacket(infos, infos.length, ia, 5000);
socket = new DatagramSocket();
socket.send(dp);
byte[] replya = new byte[100];
DatagramPacket dpt = new DatagramPacket(replya, replya.length);
socket.receive(dpt);
String reply = new String(dpt.getData(), 0, dpt.getData().length);
System.out.println("服务器回应:" + reply);
} catch (UnknownHostException e) {
throw new RuntimeException(e);
} catch (SocketException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
socket.close();
}
}
}
2)LoginClient类
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.net.SocketException;
public class LoginServer {
public static void main(String[] args) {
byte[] infos=new byte[100];
DatagramPacket dp=new DatagramPacket(infos,infos.length);
DatagramSocket socket=null;
try {
socket=new DatagramSocket(5000);
socket.receive(dp);
String reply = "您好,我在,请说!";
String info=new String(dp.getData(),0,dp.getData().length);
System.out.println("客户端说:"+info);
SocketAddress sa = dp.getSocketAddress();
DatagramPacket dpt = new DatagramPacket(reply.getBytes(), 0, reply.getBytes().length, sa);
socket.send(dpt);
} catch (SocketException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}