Socket Programming
Cangjie's socket programming enables the transfer of data packets over the network using transport layer protocols.
In a reliable transfer scenario, Cangjie separately starts a client socket and a server socket. The client socket must specify the remote address to be connected and selectively binds to the local address. Packets can be sent and received after the connection is successful. The server socket must be bound to the local address, after which packets can be sent and received.
In an unreliable transfer scenario, there is no need to distinguish between client and server sockets. Cangjie separately starts the two sockets for data transfer. Both sockets must be bound to the local address, after which packets can be sent and received. In addition, the socket may selectively specify a remote management address. After the address is specified, only packets of the specified address are accepted. When sending packets, there is no need to specify the remote address again; the packets will be automatically sent to the connected address.
TCP Programming
TCP is a common reliable transport protocol. Here we use a TCP socket as an example and provide a Cangjie programming model in a reliable transport scenario for reference.
- Create a server socket and specify the local address to be bound.
- Perform the binding.
- Perform the accept operation. The server is blocked and waits until a client socket is connected.
- Create a client socket and specify the remote address to be connected.
- Set up a connection.
- After the connection is successful, the server returns a new socket through the accept interface and performs read and write operations (sending and receiving packets) using the socket. By contrast, the client can directly perform read and write operations.
The following is an example of the TCP server and client programs:
import std.socket.*
import std.time.*
import std.sync.*
var SERVER_PORT: UInt16 = 0
func runTcpServer() {
try (serverSocket = TcpServerSocket(bindAt: SERVER_PORT)) {
serverSocket.bind()
SERVER_PORT = serverSocket.localAddress.port
try (client = serverSocket.accept()) {
let buf = Array<Byte>(10, item: 0)
let count = client.read(buf)
// 服务端读取到的数据为: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
println("Server read ${count} bytes: ${buf}")
}
}
}
main(): Int64 {
let future = spawn {
runTcpServer()
}
sleep(Duration.millisecond * 500)
try (socket = TcpSocket("127.0.0.1", SERVER_PORT)) {
socket.connect()
socket.write(Array<Byte>([1, 2, 3]))
}
future.get()
return 0
}
Compiling and executing the preceding code will display the following information:
Server read 3 bytes: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
UDP Programming
UDP is a common unreliable transport protocol. Here we use a UDP socket as an example and provide a Cangjie programming model in an unreliable transport scenario for reference.
- Create a socket and specify the local address to be bound.
- Perform the binding.
- Specify a remote address for sending packets.
- If no remote address is connected, packets from different remote addresses can be received and the remote address information can be returned.
Here is a program example that describes how a UDP receives and sends packets:
import std.socket.*
import std.time.*
import std.sync.*
let SERVER_PORT: UInt16 = 8080
func runUpdServer() {
try (serverSocket = UdpSocket(bindAt: SERVER_PORT)) {
serverSocket.bind()
let buf = Array<Byte>(3, item: 0)
let (clientAddr, count) = serverSocket.receiveFrom(buf)
let sender = clientAddr.hostAddress
// Packet received by the socket and the remote address: [1, 2, 3], 127.0.0.1
println("Server receive ${count} bytes: ${buf} from ${sender}")
}
}
main(): Int64 {
let future = spawn {
runUpdServer()
}
sleep(Duration.second)
try (udpSocket = UdpSocket(bindAt: 0)) {
udpSocket.sendTimeout = Duration.second * 2
udpSocket.bind()
udpSocket.sendTo(
SocketAddress("127.0.0.1", SERVER_PORT),
Array<Byte>([1, 2, 3])
)
}
future.get()
return 0
}