Computer Network | Code Implementation of C/S Model Based on UDP

insert image description here

Welcome to follow the blogger Mindtechnist or join [ Linux C/C++/Python Community ] to learn and share Linux, C, C++, Python, Matlab, robot motion control, multi-robot collaboration, intelligent optimization algorithm, filter estimation, multi-sensor information fusion, Knowledge and technology in machine learning, artificial intelligence and other related fields.


Realization of C/S Model Code Based on UDP


Column: "Network Programming"


UDP server

There are two main protocol models used in the transport layer, one is the TCP protocol, and the other is the UDP protocol. The TCP protocol plays a dominant role in network communication, and the vast majority of network communication uses the TCP protocol to complete data transmission. But UDP is also an indispensable means of communication in network communication.
Compared with TCP, the form of UDP communication is more like sending text messages. There is no need to establish and maintain a connection before data transmission. Just focus on getting the data. The process of three-way handshake is omitted, and the communication speed can be greatly improved, but the stability and accuracy of the accompanying communication cannot be guaranteed. Therefore, we call UDP "connectionless unreliable message delivery".
So compared with the well-known TCP, what are the advantages and disadvantages of UDP? Since there is no need to create a connection, the UDP overhead is small, the data transmission speed is fast, and the real-time performance is strong. It is mostly used in communication occasions that require high real-time performance, such as video conferencing, teleconferencing, etc. But it is also accompanied by unreliable data transmission, and the accuracy, transmission sequence and flow of transmitted data cannot be controlled and guaranteed. Therefore, under normal circumstances, the UDP protocol is used for data transmission. In order to ensure the correctness of the data, we need to add an auxiliary verification protocol at the application layer to make up for the shortcomings of UDP, so as to achieve the purpose of reliable data transmission.
Similar to TCP, UDP may also experience packet loss when receiving data after the buffer is filled. Because it does not have a TCP sliding window mechanism, the following two methods are usually used to solve it:
1) The server application layer designs flow control to control the sending data speed.
2) Use the setsockopt function to change the size of the receiving buffer. like:

#include <sys/socket.h>
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
	int n = 220x1024
	setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));

C/S model

UDP processing model

Since UDP does not need to maintain connections, the program logic is much simpler, but the UDP protocol is unreliable, and the mechanism to ensure communication reliability needs to be implemented at the application layer.
Compile and run the server, and open a client in each of the two terminals to interact with the server to see if the server has the ability to serve concurrently. Use Ctrl+C to close the server, and then run the server to see if the client can still contact the server. Compared with the running results of the TCP program, realize the meaning of no connection.

server

#include <string.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <strings.h>
#include <arpa/inet.h>
#include <ctype.h>

#define MAXLINE 80
#define SERV_PORT 6666

int main(void)
{
    
    
	struct sockaddr_in servaddr, cliaddr;
	socklen_t cliaddr_len;
	int sockfd;
	char buf[MAXLINE];
	char str[INET_ADDRSTRLEN];
	int i, n;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);

	bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
	printf("Accepting connections ...\n");

	while (1) {
    
    
		cliaddr_len = sizeof(cliaddr);
		n = recvfrom(sockfd, buf, MAXLINE,0, (struct sockaddr *)&cliaddr, &cliaddr_len);
		if (n == -1)
			perror("recvfrom error");
		printf("received from %s at PORT %d\n", 
				inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
				ntohs(cliaddr.sin_port));
		for (i = 0; i < n; i++)
			buf[i] = toupper(buf[i]);

		n = sendto(sockfd, buf, n, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
		if (n == -1)
			perror("sendto error");
	}
	close(sockfd);
	return 0;
}

client

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <ctype.h>

#define MAXLINE 80
#define SERV_PORT 6666

int main(int argc, char *argv[])
{
    
    
	struct sockaddr_in servaddr;
	int sockfd, n;
	char buf[MAXLINE];

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
	servaddr.sin_port = htons(SERV_PORT);

	while (fgets(buf, MAXLINE, stdin) != NULL) {
    
    
		n = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
		if (n == -1)
			perror("sendto error");
		n = recvfrom(sockfd, buf, MAXLINE, 0, NULL, 0);
		if (n == -1)
			perror("recvfrom error");
		write(STDOUT_FILENO, buf, n);
	}
	close(sockfd);
	return 0;
}

multicast (multicast)

Multicast groups can be permanent or temporary. Some of the multicast group addresses are officially assigned and are called permanent multicast groups. What remains unchanged in a permanent multicast group is its ip address, and the composition of members in the group can change. The number of members in a permanent multicast group can be arbitrary, even zero. Those ip multicast addresses that are not reserved for permanent multicast groups can be used by temporary multicast groups.

224.0.0.0~224.0.0.255 are reserved multicast addresses (permanent group addresses), the address 224.0.0.0 is reserved and not allocated, and other addresses are used by routing protocols; 224.0.1.0~224.0.1.255
are public multicast addresses, which can be For use on the Internet; an application is required for use.
224.0.2.0~238.255.255.255 are user-available multicast addresses (temporary group addresses), which are valid within the entire network;
239.0.0.0~239.255.255.255 are local management multicast addresses, which are only valid within a specific local area.

You can use the ip ad command to view the network card number, such as:

itcast$ ip ad
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
link/ether 00:0c:29:0a:c4:f4 brd ff:ff:ff:ff:ff:ff
inet6 fe80::20c:29ff:fe0a:c4f4/64 scope link
valid_lft forever preferred_lft forever

The if_nametoindex command can obtain the serial number of the network card according to the name of the network card.

server

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <net/if.h>

#define SERVER_PORT 6666
#define CLIENT_PORT 9000
#define MAXLINE 1500
#define GROUP "239.0.0.2"

int main(void)
{
    
    
	int sockfd, i ;
	struct sockaddr_in serveraddr, clientaddr;
	char buf[MAXLINE] = "itcast\n";
	char ipstr[INET_ADDRSTRLEN]; /* 16 Bytes */
	socklen_t clientlen;
	ssize_t len;
	struct ip_mreqn group;

	/* 构造用于UDP通信的套接字 */
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	bzero(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET; /* IPv4 */
	serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); /* 本地任意IP INADDR_ANY = 0 */
	serveraddr.sin_port = htons(SERVER_PORT);

	bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

	/*设置组地址*/
	inet_pton(AF_INET, GROUP, &group.imr_multiaddr);
	/*本地任意IP*/
	inet_pton(AF_INET, "0.0.0.0", &group.imr_address);
	/* eth0 --> 编号 命令:ip ad */
	group.imr_ifindex = if_nametoindex("eth0");
	setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, &group, sizeof(group));

	/*构造 client 地址 IP+端口 */
	bzero(&clientaddr, sizeof(clientaddr));
	clientaddr.sin_family = AF_INET; /* IPv4 */
	inet_pton(AF_INET, GROUP, &clientaddr.sin_addr.s_addr);
	clientaddr.sin_port = htons(CLIENT_PORT);

	while (1) {
    
    
		//fgets(buf, sizeof(buf), stdin);
		sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&clientaddr, sizeof(clientaddr));
		sleep(1);
	}
	close(sockfd);
	return 0;
}

client

#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <net/if.h>

#define SERVER_PORT 6666
#define MAXLINE 4096
#define CLIENT_PORT 9000
#define GROUP "239.0.0.2"

int main(int argc, char *argv[])
{
    
    
	struct sockaddr_in serveraddr, localaddr;
	int confd;
	ssize_t len;
	char buf[MAXLINE];

	/* 定义组播结构体 */
	struct ip_mreqn group;
	confd = socket(AF_INET, SOCK_DGRAM, 0);

	//初始化本地端地址
	bzero(&localaddr, sizeof(localaddr));
	localaddr.sin_family = AF_INET;
	inet_pton(AF_INET, "0.0.0.0" , &localaddr.sin_addr.s_addr);
	localaddr.sin_port = htons(CLIENT_PORT);

	bind(confd, (struct sockaddr *)&localaddr, sizeof(localaddr));

	/*设置组地址*/
	inet_pton(AF_INET, GROUP, &group.imr_multiaddr);
	/*本地任意IP*/
	inet_pton(AF_INET, "0.0.0.0", &group.imr_address);
	/* eth0 --> 编号 命令:ip ad */
	group.imr_ifindex = if_nametoindex("eth0");
	/*设置client 加入多播组 */
	setsockopt(confd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));

	while (1) {
    
    
		len = recvfrom(confd, buf, sizeof(buf), 0, NULL, 0);
		write(STDOUT_FILENO, buf, len);
	}
	close(confd);
	return 0;
}

insert image description here
insert image description here


Guess you like

Origin blog.csdn.net/qq_43471489/article/details/130641167