Linux基础网络编程:Linux下UDP网络编程模型

前面写了一篇关于TCP/IP协议的网络编程模型,本来打算UDP这块不去写的,感觉会用的少,但是很扎心的就是,去一家公司笔试和面试的时候,笔试题中有关于这一个知识点的内容,很简单的一道题,但是最近对这一部分的知识点的遗忘,没太在意,就做错了,其他的题也是做的很糟糕。
先来借这里总结一下这一次面试的经历吧,那家公司的办公环境是真的舒适,在腾讯大厦,看着很高端,这是我正式面试的第一家公司,面试的岗位是嵌入式开发,公司主要是做路由和家庭网络,智能家居配套的这一块的,第一次走进这家公司,我是忐忑的,我幻想着自己一会在面试时会被提问问到懵逼,自己的自我介绍可能会因为紧张而口齿不清,(紧张主要也是没实力,真正有实力的人是不会紧张的)但是怎么也没有想到自己会卡在笔试那关的门前。对的,我笔试没过,笔试题提交以后其实我就知道笔试题大概率会过不了了,头一天接到邀请面试的时候,查了一下这个公司的业务方向,我就去仔回顾了自己简历上项目的流程,原理,用到了什么技术,相关问题的解决方法。当然,面试题也刷了不少,但主要是C以及数据结构方面的知识,所以自我感觉对于笔试部分准备还是比较充足的,笔试没过也是侧面说明了自己很多地方知识点的遗忘与知识储备的不足,所以这场面试是还没开始就结束了,来回将近三个小时的车程,就只是去做了一套面试题(还是不定项选择),所以,为了下次面试不出现这种情况就继续学习,查漏补缺吧 。。。

走出大厦的那一刻,心中的确是轻松了不少,虽然早就做好了被淘汰的心里准备,但是当真正知道的时候,还是会有失落的,也有几分苦涩,看着街道两旁高楼林立,我想,我还会不会来到这里,这里能否留下自己未来几年甚至几十年的足迹?街道上,偶尔走过几个人,阳光还是如我进去面试之前一样明媚,我回头望了望那栋楼,推了推眼镜,拽紧手中的简历,往地铁站方向走去。

好了,不继续抒情了,学习才是正事。

我们都知道网络编程模型有TCP/IP协议,和UDP协议两种,当然是各有各的好处,但也有缺点,这里先来总结一下TCP和UDP的相同和不同:

基本的区别:
TCP是一个面向连接的,可靠的,基于字节流的传输层协议; UDP是一个面向无连接的传输层协议.
具体分析的话,UDP和TCP相比,TCP有三大核心特性:
1.面向连接 所谓的连接,是指的客户端和服务器的连接,在双方通信之前,TCP需要三次握手来建立连接,而UDP没有相应建立连接的过程.
2.可靠性 第一,TCP会精准的记录哪些数据发送了,哪些数据被对方接收了,那些没有被接收到,而且会保证数据按照发送的数据的顺序到达,不会出错,这就是有状态; 第二, 当意识到丢包或者网络环境不佳,TCP会根据具体的情况调整自己的行为,控制自己的发送速度或者重发.这是可控制的. 相应的,UDP就是五状态,不可控的.
3.面向字节流 UDP的数据传输是基于数据报的,这是因为仅仅继承了IP层的特性,将一个个IP包变成了字节流.

TCP和UDP的不同,基本上面试的时候都会问到,也不用刻意的去记,大概理解到,能用自己的话说出即可;
UDP服务器和客户端的框架:
服务器
1.socket() ----------创建套接字
2.bind() ----------绑定端口和主机地址
3.recvfrom() ----------接收数据
4.sendto ----------发送数据
5.close() ----------关闭套接字

客户端
1.socket() ----------创建套接字
bind()/connect() ----------绑定端口和主机地址/建立连接(可选)
3.recvfrom() ----------接收数据
4.sendto ----------发送数据
5.close() ----------关闭套接字

两个函数
recvfrom()/sendto()

1、recvfrom: 接收数据
{
	#include <sys/types.h>
    #include <sys/socket.h>
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                     struct sockaddr *src_addr, socklen_t *addrlen);
			
	参数:  sockfd --- 套接字文件描述符
			buf	   --- 存放数据的空间首地址
			len    --- 想要接收的字节数
			flags  --- 接收方式(0)
			src_addr --- 获取发送方的地址
			addrlen  --- 获取发送方的地址的长度
	返回值:
		>0: 成功接收的字节数
		-1:失败,并设置errno
}	
	
2、sendto: 发送数据
{
	#include <sys/types.h>
    #include <sys/socket.h>
	ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);
					  
	参数: sockfd --- 套接字文件描述符
			buf   --- 发送数据的首地址
			len   --- 发送的字节数
			flags --- 发送方式(0)
			dest_addr --- 接收方的地址
			addrlen   --- 接收方的地址的长度
				
	返回值:
		成功: 成功发送的字节数
		失败: -1, 并设置errno
}

net.h

#ifndef _NET_H
#define _NET_H

#include <stdio.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define SIZE 1024

#endif

server.c

#include "net.h"

int main()
{
	//1.创建套接字
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sockfd < 0){
		perror("socket");
		return -1;
	}
	printf("socket.......................\n");

	//绑定主机地址和端口
	struct sockaddr_in myaddr = {
		.sin_family = AF_INET,
		.sin_port = htons(8888),
		.sin_addr.s_addr = htonl(INADDR_ANY)
	};
	int ret = bind(sockfd,(struct sockaddr *)&myaddr,sizeof(myaddr));
	if(ret < 0){
		perror("bind");
		return -1;
	}
	
	//3.收发数据
	char buf[SIZE];
	struct sockaddr_in cliaddr;
	int addrlen = sizeof(cliaddr);

	while(1){
		memset(buf,0,SIZE);
		ret = recvfrom(sockfd,buf,SIZE,0,(struct sockaddr*)&cliaddr,&addrlen);
		if(ret < 0){
			perror("recvfrom");
			break;
		}
		printf("recv:%s  %s\n",inet_ntoa(cliaddr.sin_addr), buf);
		memset(buf,0,SIZE);
		printf("send:");
		fgets(buf,SIZE,stdin);
		ret = sendto(sockfd, buf,SIZE, 0, (struct sockaddr *)&cliaddr,addrlen);

		if(ret < 0){
			perror("sendto");
			break;
		}

	}
	//4.关闭套接字
	close(sockfd);
	return 0;
}

client.c

int main()
{
	//1.创建套接字
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sockfd < 0){
		perror("socket");
		return -1;
	}
	printf("socket.................\n");

	//2.收发数据
	char buf[SIZE];
	int ret;
	struct sockaddr_in srcaddr = {
		.sin_family = AF_INET,
		.sin_port = htons(8888),
		.sin_addr.s_addr = inet_addr("127.0.0.1")
	};

	while(1){
		memset(buf,0,SIZE);
		printf("send:");
		fgets(buf,SIZE,stdin);
		ret = sendto(sockfd,buf,SIZE,0,(struct sockaddr*)&srcaddr,sizeof(srcaddr));
		if(ret < 0){
			perror("sendto");
			break;
		}

		ret = recvfrom(sockfd,buf,SIZE,0,NULL,NULL);
		if(ret < 0){
			perror("recvfrom");
			break;
		}
		printf("recv : %s  %s\n",inet_ntoa(srcaddr.sin_addr),buf);
	}

	//3.关闭套接字
	close(sockfd);
	return 0;
}

其实也是和TCP差不多的实现方法,只是少了accept,connect.
这些东西真的是要经常去回顾,久了不看,不去学习再简单的东西都做不好,既然选择了这条路,就一起为自己热爱的走下去吧!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值