进程通过一个称为套接字(socket)的软件接口向网络发送报文和从网络接受报文
如果将进程类比为一座房子,那么套接字可以类比为门,当进程发送报文时,进程将报文推出门。接收报文时,通过接收进程的门传递。
套接字是同一台主机内应用层与传输层之间的接口,是建立网络应用程序的可编程接口,因此套接字称为应用程序和网络之间的应用程序编程接口(Application Programming Interface,API)
python
UDP套接字编程
客户端
# socket模块形成了在Python中所有网络通信的基础
from socket import *
# 设定server名字和端口号,其中serverName可以是IP地址或者包含服务器的主机名
# 如果使用主机名,则将自动执行DNS lookup从而获得IP地址
# 这里直接使用本机地址
serverName = 'localhost'
serverPort = 12000
# 创建了客户的套接字
# 第一个参数表明是ipv4协议
# 第二个参数表明是UDP协议
clientSocket = socket(AF_INET, SOCK_DGRAM)
# 请求用户输入信息,即报文
message = input('Input lowercase sentence')
# 为报文message附上目的地址,并向套接字clientSocket发送结果分组
clientSocket.sendto(message.encode(), (serverName, serverPort))
# 套接字接收到来自互联网的消息后,获取消息和服务器地址
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
print(modifiedMessage.decode())
clientSocket.close()
服务器端
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_DGRAM)
# 将端口号12000和服务器的套接字绑定在一起,当任何人向服务器所在IP地址的端口12000发送一个分组时,分组将导向该套接字
serverSocket.bind(('', serverPort))
# 将端口号绑定后即为服务器已经打开
print("The server is ready to receive")
while True:
message, clientAddress = serverSocket.recvfrom(2048)
# 服务器将信息转为大写
modifiedMessage = message.decode().upper()
# 服务器将信息返回到客户端中
serverSocket.sendto(modifiedMessage.encode(), clientAddress)
效果
2021.11.29
TCP套接字编程
TCP是一个面向连接的协议,这意味着在客户和服务器发送数据之前,需要先进行握手并创建一个TCP连接,TCP连接的一端和客户套接字相联系,另一端和服务器套接字联系。
由于TCP是面向连接的,因此在丢进套接字时不需要附上目的地址
TCPClient.py
from socket import *
serverName = 'localhost'
serverPort = 12000
# SOCK_STREAM表示是一个tcp连接
clientSocket = socket(AF_INET, SOCK_STREAM)
# 建立TCP连接,connect函数包括了三次握手协议
clientSocket.connect((serverName, serverPort))
sentence = input('Input lowercase sentence:')
clientSocket.send(sentence.encode())
modifiedSentence = clientSocket.recv(1024)
print('From Server: ', modifiedSentence.decode())
clientSocket.close()
TCPServer
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', serverPort))
# 将服务器接收来自客户的TCP请求,参数中定义了TCP请求数最多为1
serverSocket.listen(1)
print('The server is ready to receive')
while True:
# 当用户发送连接请求时,程序调用accept方法,在服务器中创建了一个connectionSocket的套接字
# 另外,服务器和客户端在accept中完成了握手
# 此时服务器和客户端可以进行通信并且能够确保按照顺序到达
connectionSocket, addr = serverSocket.accept()
sentence = connectionSocket.recv(1024).decode()
capitalizedSentence = sentence.upper()
connectionSocket.send(capitalizedSentence.encode())
# 为这个客户端创建的套接字关闭,并且可以开始监听其他客户端传来的数据
connectionSocket.close()
2021.12.7
java
获取响应头
import java.io.*;
import java.net.*;
public final class WebServer
{
public static void main(String[] args) throws Exception {
int port = 6789;
// Construct an object to process the HTTP request message.
ServerSocket socket = new ServerSocket(port);
while (true) {
// accept方法开启服务端的监听请求
// 当成功连接时,会创建一个新的套接字,并且将该监听阻塞
// 即获取需要的套接字
Socket connection = socket.accept();
HttpRequest request = new HttpRequest(connection);
// Create a new thread to process the request.
Thread thread = new Thread(request);
// Start the thread.
thread.start();
}
}
}
final class HttpRequest implements Runnable
{
final static String CRLF = "\r\n";
Socket socket;
// Constructor
public HttpRequest(Socket socket) throws Exception
{
this.socket = socket;
}
// Implement the run() method of the Runnable interface.
public void run()
{
// . . .
try {
processRequest();
} catch (Exception e) {
e.printStackTrace();
}
}
private void processRequest() throws Exception
{
// Get a reference to the socket's input and output streams.
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
InputStreamReader isr = new InputStreamReader(is);
// Set up input stream filters.
BufferedReader br = new BufferedReader(isr);
// Get the request line of the HTTP request message.
String requestLine = br.readLine();
// Display the request line.
System.out.println();
System.out.println(requestLine);
// Get and display the header lines.
String headerLine = null;
while ((headerLine = br.readLine()).length() != 0) {
System.out.println(headerLine);
}
// Close streams and socket.
os.close();
br.close();
socket.close();
}
}