Socket
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。
TCP/IP
互联网协议(Internet Protocol Suite)是一个网络通信模型,以及一整个网络传输协议家族,为互联网的基础通信架构。它常被通称为TCP/IP协议族(英语:TCP/IP Protocol Suite,或TCP/IP Protocols),简称TCP/IP。因为该协议家族的两个核心协议:TCP(传输控制协议)和IP(网际协议),为该家族中最早通过的标准。由于在网络通讯协议普遍采用分层的结构,当多个层次的协议共同工作时,类似计算机科学中的堆栈,因此又被称为TCP/IP协议栈(英语:TCP/IP Protocol Stack) 。这些协议最早发源于美国国防部(缩写为DoD)的ARPA网项目,因此也被称作DoD模型(DoD Model)。这个协议族由互联网工程任务组负责维护。
TCP/IP提供点对点的链接机制,将数据应该如何封装、定址、传输、路由以及在目的地如何接收,都加以标准化。它将软件通信过程抽象化为四个抽象层,采取协议堆栈的方式,分别实现出不同通信协议。协议族下的各种协议,依其功能不同,被分别归属到这四个层次结构之中,常被视为是简化的七层OSI模型。
TCP
TCP是面向连接的通信协议,通过三次握手建立连接,通讯完成时要拆除连接,由于TCP是面向连接的所以只能用于端到端的通讯。
TCP提供的是一种可靠的数据流服务,采用“带重传的肯定确认”技术来实现传输的可靠性。TCP还采用一种称为“滑动窗口”的方式进行流量控制,所谓窗口实际表示接收能力,用以限制发送方的发送速度。
如果IP数据包中有已经封好的TCP数据包,那么IP将把它们向‘上’传送到TCP层。TCP将包排序并进行错误检查,同时实现虚电路间的连接。TCP数据包中包括序号和确认,所以未按照顺序收到的包可以被排序,而损坏的包可以被重传。
TCP将它的信息送到更高层的应用程序,例如Telnet的服务程序和客户程序。应用程序轮流将信息送回TCP层,TCP层便将它们向下传送到IP层,设备驱动程序和物理介质,最后到接收方。
面向连接的服务(例如Telnet、FTP、rlogin、X Windows和SMTP)需要高度的可靠性,所以它们使用了TCP。DNS在某些情况下使用TCP(发送和接收域名数据库),但使用UDP传送有关单个主机的信息。
UDP
UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送。
UDP通讯时不需要接收方确认,属于不可靠的传输,可能会出现丢包现象,实际应用中要求程序员编程验证。
UDP与TCP位于同一层,但它不管数据包的顺序、错误或重发。因此,UDP不被应用于那些使用虚电路的面向连接的服务,UDP主要用于那些面向查询—应答的服务,例如NFS。相对于FTP或Telnet,这些服务需要交换的信息量较小。使用UDP的服务包括NTP(网络时间协议)和DNS(DNS也使用TCP)。
欺骗UDP包比欺骗TCP包更容易,因为UDP没有建立初始化连接(也可以称为握手)(因为在两个系统间没有虚电路),也就是说,与UDP相关的服务面临着更大的危险。
基于TCP的socket
//Server
@Slf4j
public class Server {
private static ServerSocket server = null;
static void init() throws IOException {
synchronized (Server.class) {
if (server == null) {
server = new ServerSocket(ServerParams.PORT);
}
log.info("服务端已启动~.....");
while (true) {
Socket client = server.accept();
new ReadAndWrite(client).start();
}
}
}
public static void main(String[] args) throws IOException {
Server.init();
}
}
@Slf4j
@AllArgsConstructor
class ReadAndWrite extends Thread {
private Socket socket;
@Override
public void run() {
log.info("有客户端接入:{}", socket.getInetAddress());
try {
BufferedReader reder = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(socket.getOutputStream());
String readMsg = "";
String respMsg = "";
while (true) {
readMsg = reder.readLine();
log.info("客户端--{}---说:{}", socket.getInetAddress(), readMsg);
respMsg = readMsg + "---服务端收到!";
writer.println(respMsg);
writer.flush();
}
} catch (Exception e) {
log.error("客户端连接异常...", e);
}
}
}
//Client
@Slf4j
public class Client {
private static Socket client = null;
static void init() throws UnknownHostException, IOException {
synchronized (Client.class) {
if (client == null) {
client = new Socket(ServerParams.HOST, ServerParams.PORT);
}
log.info("客户端已启动...");
// 获取输出流---向服务端发送信息
PrintWriter writer = new PrintWriter(client.getOutputStream());
// 获取输入流---接受服务端信息
BufferedReader reder = new BufferedReader(new InputStreamReader(client.getInputStream()));
String writerMsg = "";
String respMsg = "";
while (true) {
writerMsg = new Scanner(System.in).nextLine();
writer.println(writerMsg);
writer.flush();
respMsg = reder.readLine();
log.info("服务端回复:{}", respMsg);
}
}
}
public static void main(String[] args) throws UnknownHostException, IOException {
Client.init();
}
}
server----------------------------------------------------------------------
2019-03-11 18:01:59,323 [main] INFO com.haha.socket.tcp.server.Server - 服务端已启动~.....
2019-03-11 18:02:02,834 [Thread-1] INFO com.haha.socket.tcp.server.ReadAndWrite - 有客户端接入:/127.0.0.1
2019-03-11 18:02:05,892 [Thread-2] INFO com.haha.socket.tcp.server.ReadAndWrite - 有客户端接入:/127.0.0.1
2019-03-11 18:02:10,194 [Thread-1] INFO com.haha.socket.tcp.server.ReadAndWrite - 客户端--/127.0.0.1---说:111
2019-03-11 18:02:13,510 [Thread-2] INFO com.haha.socket.tcp.server.ReadAndWrite - 客户端--/127.0.0.1---说:222
server----------------------------------------------------------------------
client1---------------------------------------------------------------------------------
2019-03-11 18:02:02,832 [main] INFO com.haha.socket.tcp.client.Client - 客户端已启动...
111
2019-03-11 18:02:10,195 [main] INFO com.haha.socket.tcp.client.Client - 服务端回复:111---服务端收到!
client1---------------------------------------------------------------------------------
client2---------------------------------------------------------------------------------
2019-03-11 18:02:05,893 [main] INFO com.haha.socket.tcp.client.Client - 客户端已启动...
222
2019-03-11 18:02:13,511 [main] INFO com.haha.socket.tcp.client.Client - 服务端回复:222---服务端收到!
client2---------------------------------------------------------------------------------
基于UDP的socket
//server
/**
* UDP
*/
@Slf4j
public class Server {
private static DatagramSocket server = null;
static void init() throws Exception {
synchronized (Server.class) {
if (server == null) {
server = new DatagramSocket(ServerParams.PORT);
}
log.info("UDP 服务端已启动...");
// 定义数据包,用于存储数据
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
while (true) {
server.receive(dp);
if (dp.getAddress() != null) {
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(), 0, dp.getLength());
log.info("收到信息:ip---{},data---{}", ip, data);
}
}
}
}
public static void main(String[] args) throws Exception {
Server.init();
}
}
//client
public class Client {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();// 通过DatagramSocket对象创建udp服务
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));// 从键盘上面输入文本
String line = null;
while ((line = bufr.readLine()) != null)// 当输入不为空时
{
if ("byebye".equals(line))// 当输入为byebye时退出程序
break;
// 确定好数据后,并把数据封装成数据包
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName(ServerParams.HOST),
ServerParams.PORT);// 发送至指定IP,指定端口
ds.send(dp);// 通过send方法将数据包发送出去
}
ds.close();// 关闭资源
}
}
server---------------------------------------------------------
2019-03-11 18:23:08,129 [main] INFO com.haha.socket.udp.server.Server - UDP 服务端已启动...
2019-03-11 18:23:12,864 [main] INFO com.haha.socket.udp.server.Server - 收到信息:ip---127.0.0.1,data---21213
2019-03-11 18:23:31,294 [main] INFO com.haha.socket.udp.server.Server - 收到信息:ip---127.0.0.1,data---21515615
2019-03-11 18:24:37,817 [main] INFO com.haha.socket.udp.server.Server - 收到信息:ip---127.0.0.1,data---5555
2019-03-11 18:24:41,690 [main] INFO com.haha.socket.udp.server.Server - 收到信息:ip---127.0.0.1,data---666
server---------------------------------------------------------
client1---------------------------------------------------------
123
21213
21515615
client1---------------------------------------------------------
client2---------------------------------------------------------
5555
666
client2---------------------------------------------------------