在上篇博客中介绍了网络编程中常用的一些函数,和TCP服务器与客户端的程序,这篇博客将介绍TCP与UDP的区别,并用实例程序进行演示。
1、TCP与UDP的区别
TCP向应用层提供可靠的面向连接的数据流传输服务。它能提供高可靠通信(即数据无误、数据无丢失、数据无失序、数据无重复到达)。TCP是面向连接的协议,所谓面向连接,就是当计算机双发通信时必须先建立连接,然后进行数据通信,最后关闭连接,TCP建立连接的过程通常被业内人士称为“三次握手”,(这里不对协议进行详细介绍,有兴趣的读者可以自行百度)
UDP是用户数据协议报,是一种无连接的不可靠传输协议,具有资源消耗小、处理速度快的特点。由于UDP通信之前不需要建立一个连接,因此UDP应用要比TCP应用更加简单。UDP比TCP更为高效,也能更好的解决实时性的问题。目前为止,包括网络视频会议系统在内的众多客户端/服务器模式的网络应用都使用的是UDP。
2、协议的选择
协议的选择应该考虑到数据可靠性、应用的实时性和网络的可靠性。
⑴对数据可靠性要求高的应用需选择TCP,而对数据的可靠性要求不高的应用可选择UDP。
⑵TCP中的三次握手、重传确认等手段可以保证数据传输的可靠性,但使用TCP会有较大的延时,因此不适合对实时性要求较高的应用。而UDP则有很好的实时性。
⑶网络状况不好的情况下需选用TCP(如在广域网等情况),网络状态好的情况下选择UDP可以减少网络负荷。
3、UDP编程实例
/*
server.c
*/
#include <stdio.h>
#include <strings.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define BUF_SIZE 128
int main(int argc, char *argv[])
{
int sockfd, connfd, ret;
struct sockaddr_in servaddr, cliaddr;
char buf[BUF_SIZE] = {0};
socklen_t peerlen;
if(argc < 3)
{
printf("Usage:%s <IP> <port>\n", argv[0]); //提示输入
exit(-1);
}
/*建立socket连接*/
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
printf("sockfd = %d\n", sockfd);
/*设置soscket_in结构体中相关参数*/
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(argv[2])); //把字符串转换成整型数,然后转换成对应的网络字节序
servaddr.sin_addr.s_addr = inet_addr(argv[1]); //sin_addr这个结构体中只有一个元素
/*绑定函数bind(),将socket描述符与本地的Ip与端口绑定*/
if((ret = bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) == -1)
{
perror("bind");
exit(-1);
}
printf("bind success\n");
/*调用accept()函数,等待客户端的连接*/
peerlen = sizeof(cliaddr);
while(1)
{
/*调用recv()函数接收客户端发送的数据*/
memset(buf, 0, sizeof(buf));
// printf("get in while \n");
if(recvfrom(sockfd, buf, BUF_SIZE, 0, (struct sockaddr*)&cliaddr, &peerlen) == -1)
{
perror("recv");
exit(-1);
}
printf("Receve a message from client: %s", buf);
memset(buf, 0, sizeof(buf));
strcpy(buf, "welcome to server\n");
sendto(sockfd, buf, BUF_SIZE, 0, (struct sockaddr*)&cliaddr, peerlen);
}
close(sockfd);
exit(0);
}
/*
client.c
*/
#include <stdio.h>
#include <strings.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define BUF_SIZE 128
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in servaddr;
char buf[BUF_SIZE] = {"hello Server\n"};
if(argc < 3)
{
printf("Usage:%s <IP> <port>\n", argv[0]); //提示执行程序是 传递的参数
exit(-1);
}
/*建立socket*/
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("socket");
exit(-1);
}
printf("listenfd = %d\n", sockfd);
/*设置soscket_in结构体中相关参数*/
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(argv[2])); //把字符串转换成整型数,然后转换成对应的网络字节序
servaddr.sin_addr.s_addr = inet_addr(argv[1]); //sin_addr这个结构体中只有一个元素
sendto(sockfd, buf, BUF_SIZE, 0, (struct sockaddr*)&servaddr, sizeof(servaddr));
/*调用recv()函数接收客户端发送的数据*/
if(recvfrom(sockfd, buf, BUF_SIZE, 0, NULL, NULL) == -1)
{
perror("recv");
exit(-1);
}
printf("Receve a message from server: %s", buf);
close(sockfd);
exit(0);
}
运行结果如下所示: