two computer hosts as server and client communicate with each
other.
With socket programmning respectively with TCP and UDP, realize the
following application:
1. client reads a line of characters (data) from its keyboard and sends
data to server
2. server receives the data
3. server converts lowercase letters to uppercase letters , and sends
the data to client
4. client receives the data and displays line on its screen
0.
First, we need to figure out the IP address of the server and
client.
In windows, we can use 'ipconfig' to get the IP address of the server
and client while in linux, we can use ifconfig to get the IP address of
the server and client.(In this experiment, the server is the physical
machine and the client is the virtual machine, and the network mode is
bridge mode)
in this experiment, the IP address of the server is:
10.136.12.124
and the IP address of the client is: 192.168.58.130
we choose 8080 as the port of the server.
use ping to check the connection between the server and the
client.
ping
if the ping is successful, we can start the socket programming.
1. Server side
1.1. Create a
socket with the socket() system call.
WORD version = MAKEWORD(2, 2); WSADATA data; if (WSAStartup(version, &data) != 0) { std::cerr << "Failed to start WSA" << std::endl; exit(1); } this->port_ = port; //protocol: 0 means TCP, 1 means UDP if(this->protocol_ == 0){ this->server_fd_ = socket(AF_INET, SOCK_STREAM, 0); }elseif(this->protocol_ == 1){ this->server_fd_ = socket(AF_INET, SOCK_DGRAM, 0); } if (this->server_fd_ == -1) { std::cerr << "Failed to create socket" << std::endl; exit(1); }
this->server_addr_.sin_family = AF_INET; //sin means socket internet this->server_addr_.sin_addr.s_addr = INADDR_ANY; this->server_addr_.sin_port = htons(this->port_);
we set the verstion of the socket to 2.2, and start the WSA, then
create a socket with the socket() system call. We can choose the
protocol of the socket, 0 means TCP, 1 means UDP.
parameters of the socket() system call:
- domain: AF_INET(ipv4), AF_INET6, AF_UNIX, AF_UNSPEC
- type: SOCK_STREAM(tcp), SOCK_DGRAM(udp), SOCK_RAW,
SOCK_SEQPACKET
- protocol: 0 means auto choose the protocol
Then we set the server address, the family is AF_INET, the address is
INADDR_ANY, and the port is the port we choose(8080).
fd means file descriptor, which is an integer that is used to access
the socket.
1.2.
Bind the socket to an address using the bind() system call. For a server
socket on the Internet, an address consists of a port number on the host
machine.
1 2 3 4 5 6 7 8 9 10
this->server_addr_.sin_family = AF_INET; //sin means socket internet this->server_addr_.sin_addr.s_addr = INADDR_ANY; this->server_addr_.sin_port = htons(this->port_);
if (bind(this->server_fd_, (struct sockaddr *) &this->server_addr_, sizeof(this->server_addr_)) < 0) { std::cerr << "Failed to bind socket" << std::endl; exit(1); }
we set the server address again, then bind the socket to the address
we set before. If the bind() system call fails, we will exit the
program.
1.3. Listen
for connections with the listen() system call.
1 2 3 4 5 6 7 8 9 10
if(this->protocol_ == 0) { std::cout << "[TCP]" << std::endl; if (listen(this->server_fd_, 10) < 0) { std::cerr << "Failed to listen" << std::endl; exit(1); } }elseif(this->protocol_ == 1){ std::cout << "[UDP]" << std::endl; } std::cout << "Server started on port " << this->port_ << std::endl;
if the protocol is TCP, we will listen for connections with the
listen() system call, the second parameter is the maximum length of the
queue of pending connections, if the queue is full, the client will be
refused to connect.
if the protocol is UDP, we will just print "[UDP]" because UDP is
connectionless.
1.4.
Accept a connection with the accept() system call. This call typically
blocks until a client connects with the server.
1 2 3 4 5 6 7 8 9 10
if(this->protocol_ == 1){ std::cerr << "UDP does not support accept" << std::endl; exit(1); } this->client_fd_ = ::accept(this->server_fd_, (struct sockaddr *) &this->client_addr_, &this->client_addr_len_); if (this->client_fd_ < 0) { std::cerr << "Failed to accept client" << std::endl; exit(1); } std::cout << "Client connected" << std::endl;
UDP does not support accept, so we will exit the program if the
protocol is UDP.
if the protocol is TCP, we will accept a connection with the accept()
system call, the second parameter is the address of the client, the
third parameter is the length of the address of the client.
we create a server object with the port and protocol we choose, then
start the server.
then we use a while loop to receive the message from the client, if
the message is 'q', we will break the loop.
if the message is not 'q', we will print the message from the client,
convert the lowercase letters to uppercase letters, send the message to
the client, and print the message from the server.
finally, we close the server.
2.Client side
We have just finished the server side with c++, now we will start the
client side with python.
2.1. Create a
socket with the socket() system call.
1 2 3 4 5 6 7 8
# protocol = socket.SOCK_STREAM # TCP protocol = socket.SOCK_DGRAM # UDP server = '127.0.0.1' port = 8080
s = socket.socket(socket.AF_INET, protocol) if protocol == socket.SOCK_STREAM: s.connect((server, port))
we can choose the protocol of the socket, socket.SOCK_STREAM means
TCP, socket.SOCK_DGRAM means UDP.
Then we create a socket with the socket() system call, the first
parameter is the family of the socket, the second parameter is the
protocol of the socket.
if the protocol is TCP, we will connect to the server with the
connect() system call.
2.2. Send and receive data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
whileTrue: message = input('Enter your message: ') if protocol == socket.SOCK_DGRAM: s.sendto(message.encode(), (server, port)) if message == 'q': break response, addr = s.recvfrom(1024) print('server: '+response.decode()) continue s.send(message.encode()) if message == 'q': break response = s.recv(1024) print('server: '+response.decode())
if the protocol is UDP, we will use sendto() to send the message to
the server, and use recvfrom() to receive the message from the
server.
if the protocol is TCP, we will use send() to send the message to the
server, and use recv() to receive the message from the server.
2.3. Close the connection.
1
s.close()
Just close the socket.
D. Results and Analysis
1. TCP
1.1. Server side
server
1.2. Client side
client
2. UDP
2.1. Server side
server-udp
2.2. Client side
client-udp
E. Conclusion
In this experiment, we have realized the communication between the
server and the client with socket programming.
We have used TCP and UDP respectively, and the results show that the
communication is successful.
classServer { private: int protocol_; int port_; // server port_ int server_fd_; // server file descriptor int client_fd_; // client file descriptor structsockaddr_in server_addr_; structsockaddr_in client_addr_; int client_addr_len_; char buffer_[1024]; int buffer_size_ = 1024;