一个进程中同时使用UDP和TCP传输数据

    UDP是无连接的传输,在传输的过程中数据报可能会出现丢失,但是UDP传输又适合那些实时性要求比较高的周期性发送数据的情况。比如客户端周期发送固定长度的脉冲信号给服务器,偶尔丢失一两包数据也不会造成很大的问题,在这种时候是可以使用UDP传输的。有时,客户端也需要发送控制命令给服务端,但是控制不能丢失,这时就需要使用TCP协议来传输了。下面的这个示例代码是在一个进程中同时使用TCP和UDP来传输数据。

/*=============================================================================
#     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);
		}
	}
}
我们调用select函数来监听TCP和UDP的可读条件,然后TCP的连接创建一个新的进程去处理。严格意义上来说其实也不是使用一个进程来处理。

在这里TCP和UDP我们使用的都是同一个端口。在TCP/UDP中使用5元组来定位一个连接,src_ip, src_port, dest_ip, dest_port, protocol_type,这里的protocol_type  不同,所以即使他们使用同一个端口号,他们也不会冲突。

猜你喜欢

转载自blog.csdn.net/li_wen01/article/details/55047815
今日推荐