socket概述
socket可以实现客户/服务器模式应用,Socket 是基于TCP/ip的传输层协议,可以实现基于tcp、udp的通信(简单理解Socket)。
socket流程
socket是针对客户/服务器而设计的,客户端使用socket方式调用服务端的接口,下图是java中socket的调用过程:基本流程:
- 第一步:服务端创建serverSocket,启动服务、监听端口
- 第二步:客户端创建socket,连接服务端
- 第三步:客户端通过outputstream发送数据至服务端
- 第四步:服务端通过inputstream接收客户端发送的数据
- 第五步:服务端处理完毕通过outputstream发送数据至客户端
- 第六步:客户端通过inputstream接收服务端发送的数据
socket优缺点
优点
- Socket采用tcp、udp底层协议通信,传输速度快,适用于传输大数量的数据。
- socket具有平台无关性,java写的socket的客户端可以访问c写的socket服务端。
缺点
接口传输的数据需要手动解析,socket通信的接口协议需要自定义,比如:自定义一种字符串拼接的格式,比如自定义的xml数据,自定义麻烦之处在接口调用方和接口服务端需要互相讨论确定接口的协议内容,不方便,好处:适用于传输大数量的数据。
socket examples
基于tcp传输
server
package socket;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception {
//创建socket服务端对象
ServerSocket serverSocket = new ServerSocket(1234);
System.out.println("server start!");
while(true){
//监听客户端连接,accept方法为阻塞方法
Socket socket = serverSocket.accept();
//获取输入流准备取客户端发送的数据
DataInputStream serverInputStream =null;
DataOutputStream serverOutputStream =null;
try {
//包括为datainputstream
serverInputStream = new DataInputStream(socket.getInputStream());
//读取数据
String in_data = serverInputStream.readUTF();
//打印读取的数据
System.out.println("from client.."+in_data+ "...time=" + System.currentTimeMillis());
//创建输出流准备输出数据
serverOutputStream = new DataOutputStream(socket.getOutputStream());
String returnValue = "I am fine!";
System.out.println("server write 5 seconds later: "+System.currentTimeMillis());
Thread.sleep(5000);
serverOutputStream.writeUTF(returnValue);
System.out.println("to client..."+returnValue+ "...time=" + System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
}finally{
//释放资源
if(serverInputStream!=null){
serverInputStream.close();
}
if(serverOutputStream!=null){
serverOutputStream.close();
}
}
}
}
}
client
package socket;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
boolean flag =true;
while (flag) {
// socket客户端对象
Socket socket = null;
// 输出流用于发送数据
DataOutputStream clientOutputStream = null;
// 输入流用于接收数据
DataInputStream clientInputStream = null;
try {
// 创建socket
socket = new Socket("127.0.0.1", 1234);
socket.setSoTimeout(10000);// 超时时间为10秒,防止服务端处理超时返回数据失败
// 创建输出流准备向服务端发送数据
clientOutputStream = new DataOutputStream(socket.getOutputStream());
String send = "Are you OK ?";
System.out.println("client write 5 seconds later: "+System.currentTimeMillis());
Thread.sleep(5000);
clientOutputStream.writeUTF(send);
System.out.println("to server...." + send + "...time=" + System.currentTimeMillis());
// 接收服务端发送的数据
clientInputStream = new DataInputStream(socket.getInputStream());
String resultString = clientInputStream.readUTF();
System.out.println("from server..." + resultString+ "...time=" + System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放资源
if (socket != null) {
socket.close();
}
if (clientInputStream != null) {
clientInputStream.close();
}
if (clientOutputStream != null) {
clientOutputStream.close();
}
}
flag = false;
}
}
}
先启动server,再启动client,根据打印结果,按照时间序打印
- //服务启动
- server start!...time=1501751722297
- //客户端准备发起请求
- client write 5 seconds later: 1501751727142
- //客户端发起请求
- to server....Are you OK ?...time=1501751732142
- //服务端接收请求
- from client..Are you OK ?...time=1501751732142
- //服务端准备发送请求响应
- server write 5 seconds later: 1501751732143
- //服务端发送请求响应
- to client...I am fine!...time=1501751737143
- //客户端接收响应
- from server...I am fine!...time=1501751737143
根据打印结果分析,开始server 阻塞等待连接(serverSocket.accept()),client建立连接开始通讯(clientOutputStream.writeUTF(send)),sever处理client通讯(serverInputStream.readUTF(),此响应在clientOutputStream.writeUTF(send)成功之后发生),server响应client通讯(serverOutputStream.writeUTF(returnValue)),client接收响应结果(clientInputStream.readUTF(),此响在serverOutputStream.writeUTF(returnValue)之后),至此通讯结束,关流关socket.
以上server与client进行了三次交互,也就是TCP的经典三次握手(不知道这么理解对不对...囧)
基于udp传输
package socket;
/*
* 实现UDP的发送端
*/
import java.net.*;
public class UDPSend {
public static void main(String[] args)throws Exception {
//创建数据包对象,字节数组,IP,端口号封装到数据包中
byte[] bytes = "你好UDP".getBytes();
DatagramPacket dp = new
DatagramPacket(bytes, bytes.length,InetAddress.getByName("127.0.0.1"),10000);
//创建DatagramSocket对象,发包的
DatagramSocket ds = new DatagramSocket();
//调用方法send传递数据包
ds.send(dp);
ds.close();
}
}
server
package socket;
/*
* 实现UDP接收端
*
* java.net.BindException
* 端口被占用异常
*/
import java.net.*;
public class UDPReceive {
public static void main(String[] args) throws Exception{
DatagramSocket ds = new DatagramSocket(10000);
while(true){
//定义字节数组,接收传递过来的数组
byte[] bytes = new byte[10];
//创建数据包对象,接收发送的字节数组
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//创建Socket服务机制DatagramSocket,接收数据包
//构造方法中,传递int值,端口号
//调用ds方法 receive接收数据包
ds.receive(dp);
//拆解数据包。
//获取接收到的字节数组有效个数'
int length = dp.getLength();
//获取发送端端口号
int port = dp.getPort();
//获取发送端的IP地址对象
InetAddress i = dp.getAddress();
String ip = i.getHostAddress();
System.out.println(new String(bytes,0,length)+".."+port+".."+ip);
}
}
}