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();
}
}