UDP is a connectionless transmission, and datagrams may be lost during transmission, but UDP transmission is suitable for those situations where data is sent periodically with high real-time requirements. For example, the client periodically sends a fixed-length pulse signal to the server. Occasional loss of one or two packets of data will not cause a big problem. In this case, UDP can be used for transmission. Sometimes, the client also needs to send control commands to the server, but the control cannot be lost, then the TCP protocol needs to be used for transmission. The sample code below is to use both TCP and UDP to transfer data in one process.
/*============================================================================= # FileName: tcpudpselect.c # Desc: use tcp and udp to process client request # Author: Licaibiao # LastChange: 2017-02-12 =============================================================================*/ #include<stdio.h> #include<sys/types.h> #include<sys/socket.h> #include<unistd.h> #include<stdlib.h> #include<errno.h> #include<arpa/inet.h> #include<netinet/in.h> #include<string.h> #include<signal.h> #define MAXLINE 1024 #define LISTENLEN 10 #define SERV_PORT 6666 int max(int a, int b) { return a>b ? a : b; } void sig_chld(int signo) { pid_t pid; int stat; while ((pid = waitpid(-1,stat,WNOHANG))>0) { //printf("child %d terminated \n",pid); } return ; } void str_echo(int fd) { } int main(int argc, char **argv) { int listenfd, connfd, udpfd, nready, maxfdp1; char mesg[MAXLINE]; pid_t childpid; fd_set rset; ssize_t n; socklen_t len; const int on = 1; struct sockaddr_in cliaddr, servaddr; void sig_chld(int); /* create listening TCP socket */ listenfd = socket (AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); bind(listenfd, (struct sockaddr*) &servaddr, sizeof(servaddr)); listen(listenfd, LISTENLEN); /* create UDP socket */ udpfd = 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(udpfd, (struct sockaddr*) &servaddr, sizeof(servaddr)); signal(SIGCHLD, sig_chld); /* must call waitpid() */ FD_ZERO(&rset); maxfdp1 = max(listenfd, udpfd) + 1; for ( ; ; ) { FD_SET(listenfd, &rset); FD_SET(udpfd, &rset); if ( (nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) { if (errno == EINTR) continue; /* back to for() */ else { printf("select error"); exit(0); } } if (FD_ISSET(listenfd, &rset)) { len = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr*) &cliaddr, &len); if ( (childpid = fork()) == 0) /* child process */ { close(listenfd); /* close listening socket */ str_echo(connfd); /* process the request */ exit(0); } close(connfd); /* parent closes connected socket */ } if (FD_ISSET(udpfd, &rset)) { len = sizeof(cliaddr); n = recvfrom(udpfd, mesg, MAXLINE, 0, (struct sockaddr*) &cliaddr, &len); sendto(udpfd, mesg, n, 0, (struct sockaddr*) &cliaddr, len); } } }We call the select function to listen for TCP and UDP readability conditions, and then the TCP connection creates a new process to handle. Strictly speaking, it is not actually handled by a process.
Here we use the same port for both TCP and UDP. In TCP/UDP, a 5-tuple is used to locate a connection, src_ip, src_port, dest_ip, dest_port, protocol_type, where the protocol_type is different, so even if they use the same port number, they will not conflict.