Socket通常也称作(套接字),用于描述IP地址和端口,是一个通信链的句柄。是进程通讯的一种方式,即调用这个网络库的一些API函数实现分布在不同主机的相关进程之间的数据交换。
首先,了解一下以下几个概念:
什么是TCP/IP、UDP?
TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。
UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。
Socket到底是什么呢?
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
形象一点说:“TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。这个就像操作系统会提供标准的编程接口,比如win32编程接口一样,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。”
Socket的运行机制
服务器端:
1.初始化Socket。
2.端口绑定(bind)。
3.对端口进行监听(listen)。
4.调用accept阻塞。
5.等待客户端连接。
客户端:
6.初始化一个Socket。
7.连接服务器(connect)。
此时,如果连接成功,则客户端和服务器端就连接成功了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
现在用Java分别实现基于TCP和UDP协议。
1.基于TCP协议的
简单模拟web服务器接收http请求和回发http响应的
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; public class SocketSample { public static void main(String[] args) throws IOException { // 定义一个ServerSocket监听在端口8080上 ServerSocket serverSocket = new ServerSocket(8080); while (true) { // server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的 Socket socket = serverSocket.accept(); InputStream in = socket.getInputStream(); // 跟客户端建立好连接之后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了。 BufferedReader reader = new BufferedReader( new InputStreamReader(in)); StringBuilder sb = new StringBuilder(); boolean isContent = false; String str = reader.readLine(); // 请求内容的长度 int contentLength = 0; // 读取请求内容长度的基数器 int count = 0; while (!"\r\n".equals(str)) { // 在控制台中输出得到的http请求内容。 if (isContent) { System.out.print(str); } else { System.out.println(str); } if (str.indexOf("Content-Length: ") >= 0) { // 获得httpContent的长读,用来判断阻塞式流是否将http请求内容读完。 contentLength = Integer.parseInt(str.replace( "Content-Length: ", "")); } if ("".equals(str)) { isContent = true; } if (isContent) { sb.append(str); } if (isContent) { if (contentLength == count) { // 请求内容读取结束,跳出循环 break; } str = String.valueOf((char) reader.read()); count++; } else { str = reader.readLine(); } } // 获得一个输出流,用来向客户端输出响应内容。 OutputStreamWriter out = new OutputStreamWriter(socket .getOutputStream()); out.write(sb.toString()); out.flush(); out.close(); reader.close(); socket.close(); } // serverSocket.close(); } }
html代码
<html> <head> <title>hello world</title> </head> <body> <form action="http://localhost:8080/" method="post"> <input type="text" name="userName" value="Mr wang"/> <input type="submit" value="submit"/> </form> </body> </html>
2.基于UDP协议的
package udp; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class Server { public static void main(String[] args) throws IOException { DatagramSocket server = new DatagramSocket(5050); byte[] recvBuf = new byte[100]; DatagramPacket recvPacket = new DatagramPacket(recvBuf, recvBuf.length); server.receive(recvPacket); String recvStr = new String(recvPacket.getData(), 0, recvPacket .getLength()); System.out.println("Server:" + recvStr); int port = recvPacket.getPort(); InetAddress addr = recvPacket.getAddress(); String sendStr = "Hello ! I'm Server"; byte[] sendBuf; sendBuf = sendStr.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, addr, port); server.send(sendPacket); server.close(); } }
package udp; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class Client { public static void main(String[] args) throws IOException { DatagramSocket client = new DatagramSocket(); String sendStr = "Hello! I'm Client"; byte[] sendBuf; sendBuf = sendStr.getBytes(); InetAddress addr = InetAddress.getByName("127.0.0.1"); int port = 5050; DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, addr, port); client.send(sendPacket); byte[] recvBuf = new byte[100]; DatagramPacket recvPacket = new DatagramPacket(recvBuf, recvBuf.length); client.receive(recvPacket); String recvStr = new String(recvPacket.getData(), 0, recvPacket .getLength()); System.out.println("Client:" + recvStr); client.close(); } }