1 Socket概述
(1)在计算机网络编程技术中,两个进程或者说两台计算机可以通过一个网络通信连接实现数据的交换,这种通信链路的端点就被称为“套接字”(Socket)。
(2)Socket是网络驱动层提供给应用程序的一个接口或者说一种机制。
(3)使用物流送快递的例子来说明Socket:
-->发件人将有收货人地址信息的货物送到快递站,发件人不用关心物流是如何进行的,货物被送到收货人所在地区的快递站点,进行配送,收货人等待收货就可以了。
-->这个过程很形象地说明了信息在网络中传递的过程。其中,货物就是数据信息,2个快递站点就是2个端点Socket。
2 java.net包
(1)java.net包提供了若干支持基于套接字的客户端/服务器通信的类。
(2)java.net包中常用的类有Socket、ServerSocket、DatagramPacket、DatagramSocket、InetAddress、URL、URLConnection和URLEncoder等。
(2)为了监听客户端的连接请求,可以使用ServerSocket类。
(3)Socket类实现用于网络上进程间通信的套接字。
(4)DatagramSocket类使用UDP协议实现客户端和服务器套接字。
(5)DatagramPacket类使用DatagramSocket类的对象封装设置和收到的数据报。
(6)InetAddress类表示Internet地址。
(7)在创建数据报报文和Socket对象时,可以使用InetAddress类。
3 基于TCP协议的Socket编程
3.1 Socket类和ServerSocket类
(1)java.net包的两个类Socket和ServerSocket,分别用来实现双向安全连接的客户端和服务器端,它们是基于TCP协议进行工作的,工作过程如同打电话的过程,只有双方都接通了,才能开始通话。
(2)进行网络通信时,Socket需要借助数据流来完成数据的传递工作。
(3)一个应用程序要通过网络向另一个应用程序发送数据,只要简单地创建Socket,然后将数据写入到与该Socket关联的输出流即可。对应的,接收方的应用程序创建Socket,从相关联的输入流读取数据即可。
(4)注意:2个端点在基于TCP协议的Socket编程中,经常一个作为客户端,一个作为服务器端,也就是遵循client-server模型。
3.1.1 Socket类
Socket对象在客户端和服务器之间建立连接。可用Socket类的构造方法创建套接字,并将此套接字连接至指定的主机和端口。
1)构造方法
以主机名和端口号作为参数来创建一个Socket对象。创建对象时可能抛出UnknownHostException或IOException异常,必须捕获它们。
Socket s = new Socket(hostName,port);
以InetAddress对象和端口号作为参数来创建一个Socket对象。构造方法可能抛出IOException或UnknownHostException异常,必须捕获并处理它们。
Socket s = new Socket(address,port);
2)常用方法
InetAddress getInetAddress(); 返回与Socket对象关联的InetAddress对象
int getPort(); 返回此Socket对象的远程端口
int getLocalPort(); 返回此Socket对象的本地端口
InputStream getInputStream(); 返回与此Socket对象相关联的输入流
OutputStream getOutputStream(); 返回与此Socket对象相关联的输出流
void close(); 关闭Socket
3.1.2 ServerSocket类
ServerSocket对象用于等待客户端建立连接,连接建立后进行通信。
1)构造方法
ServerSocket ss = new ServerSocket(port);以端口号作为参数,此端口号和Socket对象的端口号相对应。
ServerSocket ss = new ServerSocket(port,maxqu);以端口号和最大队列长度最为参数,队列长度表示系统在拒绝连接前可以拥有的客户端连接数。
2)常用方法
Socket accept();用于等待客户端发起通信,返回值是Socket对象。起到监听的作用,一旦监听到,则与客户端建立连接进行数据传输。
3.2 使用Socket编程实现登录
3.2.1 实现单客户端通信
Socket网络编程一般分为以下4个步骤:
(1)建立连接。
(2)打开Socket关联的输入/输出流。
(3)从数据流中写入信息和读取信息。
(4)关闭所有的数据流和Socket。
客户端:
1)建立连接,连接指定服务器及端口;
2)打开与Socket对象关联的输出流;
3)向输出流中写入数据;
4)打开与Socket对象关联的输入流;
5) 读取指定服务器的响应信息;
6)关闭所有数据流和Socket。
服务器端:
1)建立连接;
2)使用accept()方法监听等待客户端发起通信;
3)打开Socket关联的输入流;
4)读取客户端发来的数据;
5)打开Socket关联的输出流;
6)向输出流中写入响应信息;
7)关闭所有数据流、Socket和ServerSocket;
3.2.2 实现多客户端通信
一个服务器通常情况下都是面向很多的客户端同时提供服务,采用多线程的方式即可实现这一需求。在服务器端只做两件事:负责监听,负责响应。
客户端的实现步骤不变。
服务器端的实现步骤:
1)创建服务器线程类,run()方法中实现对一个客户端的请求的响应处理;
2)创建服务器类,修改服务器端代码,让服务器端一直处于监听状态;
3)服务器端每监听到一个请求,创建一个线程对象并启动;
部分代码参考:
//多个客户端向服务器发送信息,可以使用多线程,此时,服务器只需要负责侦听,侦听到哪个客户端,就执行哪个客户端线程
//这个客户端线程里需要写服务器端接收信息和发送响应信息的代码
public class ServerThread extends Thread {
Socket socket = null;// 初始化socket
// ServerThread线程的有参构造方法需要传递一个Socket类型的参数
public ServerThread(Socket socket) {
this.socket = socket;
}
// run()方法里写服务器端的响应
@Override
public void run() {
InputStream is = null;
ObjectInputStream ois = null;
OutputStream os = null;
try {
// 打开输入流
is = socket.getInputStream();
// 反序列化
ois = new ObjectInputStream(is);
// 读取用户信息
Object object = ois.readObject();
User user = (User) object;
System.out.println("用户名:" + user.getUserName() + ",密码:"
+ user.getPassword());
// 向客户端发送响应信息
os = socket.getOutputStream();
String str = "欢迎你,登陆成功";
byte[] bytes = str.getBytes();
os.write(bytes);
} 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();
}
}
}
}
//服务器端只需要负责侦听客户端
public static void main(String[] args) {
ServerSocket serverSocket=null;
try {
//创建ServerSocket对象
serverSocket=new ServerSocket(9000);
//服务器一直侦听
while(true){
Socket socket=serverSocket.accept();
ServerThread st=new ServerThread(socket);
st.start();//侦听到客户端就启动线程
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}