Use Sockets to send and receive data over TCP
Before you can use a socket to communicate with remote devices, the socket must be initialized with protocol and network address information. The constructor for the Socket class has parameters that specify the address family, socket type, and protocol type that the socket uses to make connections. When connecting a client socket to a server socket, the client will use an IPEndPoint
object to specify the network address of the server.
Create an IP endpoint
When working with System.Net.Sockets, you represent a network endpoint as an IPEndPoint object. The IPEndPoint
is constructed with an IPAddress and its corresponding port number. Before you can initiate a conversation through a Socket, you create a data pipe between your app and the remote destination.
TCP/IP uses a network address and a service port number to uniquely identify a service. The network address identifies a specific network destination; the port number identifies the specific service on that device to connect to. The combination of network address and service port is called an endpoint, which is represented in the .NET by the EndPoint class. A descendant of EndPoint
is defined for each supported address family; for the IP address family, the class is IPEndPoint.
The Dns class provides domain-name services to apps that use TCP/IP internet services. The GetHostEntryAsync method queries a DNS server to map a user-friendly domain name (such as "host.contoso.com") to a numeric Internet address (such as 192.168.1.1
). GetHostEntryAsync
returns a Task<IPHostEntry>
that when awaited contains a list of addresses and aliases for the requested name. In most cases, you can use the first address returned in the AddressList array. The following code gets an IPAddress containing the IP address for the server host.contoso.com
.
IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];
Tip
For manual testing and debugging purposes, you can typically use the GetHostEntryAsync method with the resulting host name from the Dns.GetHostName() value to resolve the localhost name to an IP address. Consider the following code snippet:
var hostName = Dns.GetHostName();
IPHostEntry localhost = await Dns.GetHostEntryAsync(hostName);
// This is the IP address of the local machine
IPAddress localIpAddress = localhost.AddressList[0];
The Internet Assigned Numbers Authority (IANA) defines port numbers for common services. For more information, see IANA: Service Name and Transport Protocol Port Number Registry). Other services can have registered port numbers in the range 1,024 to 65,535. The following code combines the IP address for host.contoso.com
with a port number to create a remote endpoint for a connection.
IPEndPoint ipEndPoint = new(ipAddress, 11_000);
After determining the address of the remote device and choosing a port to use for the connection, the app can establish a connection with the remote device.
Create a Socket
client
With the endPoint
object created, create a client socket to connect to the server. Once the socket is connected, it can send and receive data from the server socket connection.
using Socket client = new(
ipEndPoint.AddressFamily,
SocketType.Stream,
ProtocolType.Tcp);
await client.ConnectAsync(ipEndPoint);
while (true)
{
// Send message.
var message = "Hi friends 👋!<|EOM|>";
var messageBytes = Encoding.UTF8.GetBytes(message);
_ = await client.SendAsync(messageBytes, SocketFlags.None);
Console.WriteLine($"Socket client sent message: \"{message}\"");
// Receive ack.
var buffer = new byte[1_024];
var received = await client.ReceiveAsync(buffer, SocketFlags.None);
var response = Encoding.UTF8.GetString(buffer, 0, received);
if (response == "<|ACK|>")
{
Console.WriteLine(
$"Socket client received acknowledgment: \"{response}\"");
break;
}
// Sample output:
// Socket client sent message: "Hi friends 👋!<|EOM|>"
// Socket client received acknowledgment: "<|ACK|>"
}
client.Shutdown(SocketShutdown.Both);
The preceding C# code:
Instantiates a new
Socket
object with a givenendPoint
instances address family, the SocketType.Stream, and ProtocolType.Tcp.Calls the Socket.ConnectAsync method with the
endPoint
instance as an argument.In a
while
loop:- Encodes and sends a message to the server using Socket.SendAsync.
- Writes the sent message to the console.
- Initializes a buffer to receive data from the server using Socket.ReceiveAsync.
- When the
response
is an acknowledgment, it is written to the console and the loop is exited.
Finally, the
client
socket calls Socket.Shutdown given SocketShutdown.Both, which shuts down both send and receive operations.
Create a Socket
server
To create the server socket, the endPoint
object can listen for incoming connections on any IP address but the port number must be specified. Once the socket is created, the server can accept incoming connections and communicate with clients.
using Socket listener = new(
ipEndPoint.AddressFamily,
SocketType.Stream,
ProtocolType.Tcp);
listener.Bind(ipEndPoint);
listener.Listen(100);
var handler = await listener.AcceptAsync();
while (true)
{
// Receive message.
var buffer = new byte[1_024];
var received = await handler.ReceiveAsync(buffer, SocketFlags.None);
var response = Encoding.UTF8.GetString(buffer, 0, received);
var eom = "<|EOM|>";
if (response.IndexOf(eom) > -1 /* is end of message */)
{
Console.WriteLine(
$"Socket server received message: \"{response.Replace(eom, "")}\"");
var ackMessage = "<|ACK|>";
var echoBytes = Encoding.UTF8.GetBytes(ackMessage);
await handler.SendAsync(echoBytes, 0);
Console.WriteLine(
$"Socket server sent acknowledgment: \"{ackMessage}\"");
break;
}
// Sample output:
// Socket server received message: "Hi friends 👋!"
// Socket server sent acknowledgment: "<|ACK|>"
}
The preceding C# code:
Instantiates a new
Socket
object with a givenendPoint
instances address family, the SocketType.Stream, and ProtocolType.Tcp.The
listener
calls the Socket.Bind method with theendPoint
instance as an argument to associate the socket with the network address.The Socket.Listen() method is called to listen for incoming connections.
The
listener
calls the Socket.AcceptAsync method to accept an incoming connection on thehandler
socket.In a
while
loop:- Calls Socket.ReceiveAsync to receive data from the client.
- When the data is received, it's decoded and written to the console.
- If the
response
message ends with<|EOM|>
, an acknowledgment is sent to the client using the Socket.SendAsync.
Run the sample client and server
Start the server application first, and then start the client application.
dotnet run --project socket-server
Socket server starting...
Found: 172.23.64.1 available on port 9000.
Socket server received message: "Hi friends 👋!"
Socket server sent acknowledgment: "<|ACK|>"
Press ENTER to continue...
The client application will send a message to the server, and the server will respond with an acknowledgment.
dotnet run --project socket-client
Socket client starting...
Found: 172.23.64.1 available on port 9000.
Socket client sent message: "Hi friends 👋!<|EOM|>"
Socket client received acknowledgment: "<|ACK|>"
Press ENTER to continue...