【Unix 网络编程】UDP 客户/服务器简单 Socket 程序

UDP 是无连接不可靠的数据包协议,不同于 TCP 提供的面向连接的可靠字节流。在介绍UDP编程模型前,先介绍UDP协议中两个重要的函数:sendto 和 recvfrom。

#include <sys/socket.h>

ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags,
	const struct sockaddr *to, socklen_t addrlen);

ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags,
	struct sockaddr *from, socklen_t *addrlen);

//两者均返回:读写字节数——成功,-1——出错
前面三个参数:sockfd、buff 和 nbytes 等同于 read 和 write 函数的三个参数:套接口描述字、指向读入或写出缓冲区的指针和读写字节数。

sendto :其中 to 参数指向一个含有数据包接收者的协议地址(含 IP 地址和端口号)的套接口地址结构,其大小由 addrlen 参数指定。

recvfrom:from 参数指向一个将由该函数在返回时填写数据包发送者的协议地址(含数据发送端的 IP地址和端口号)的套接口地址结构,而在该套接口地址结构中填写的字节数则放在 addrlen 参数所指的整数中返回给调用者。简单地说就是 from 参数指向的结构体在 recvfrom 函数返回时将被对端(即:数据发送端)地址(含 IP 地址和端口号)所填充,后面的 addrlen 是个整型指针,调用前应填入 from 指向的结构体的大小,调用后将被填入对端地址的实际大小。

上面的 recvfrom 函数最后两个参数类似于 accept 的最后两个参数:函数返回时其中套接口地址结构的内容告诉我们是谁发送了数据包(UDP,通常用于UDP情况下)。

我们看看 UDP 编程模型:

                                                                                 

相比TCP,对于服务器而言,UDP

  • 没有调用 accept ,因为不需要建立连接,一个套接口可以接收不同 IP 发来的数据,对端 socket 地址由 recvfrom 获得。

对于客户端而言

  • 没有调用 connect,因为不需要建立连接,首次发送数据时,由操作系统临时选择本地 IP 地址和端口,由 sendto 指定目标 IP 地址和端口,因此一个套接口可以向不同 IP 发送数据。
程序如下(编程环境:Linux deepin 2014)
服务器端:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

#define PORT 8888
#define MAX_SIZE 1024

void udp_respon(int sockfd)
{
	struct sockaddr_in cliaddr;
	int n,i;
	unsigned int addrlen;
	char msg[MAX_SIZE];
	while(1)
	{     
		n = recvfrom(sockfd, msg, MAX_SIZE, 0, (struct sockaddr *)&cliaddr, &addrlen);
		msg[n] = '\0';

		fprintf(stdout, "I have recevied %s", msg);

		n = strlen(msg);
		for(i = 0; i < n; ++i)
		{
			msg[i] = msg[i] + 'A' - 'a';
		}
		sendto(sockfd, msg, n, 0, (struct sockaddr *)&cliaddr, addrlen);
	}
}

int main(void)
{
	int sockfd;
	struct sockaddr_in seraddr;

	sockfd = socket(AF_INET, SOCK_DGRAM,0);

	bzero(&seraddr, sizeof(seraddr));
	
	//服务器端套接口结构体初始化
	seraddr.sin_family = AF_INET;
	seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
	seraddr.sin_port = htons(PORT);
	
	//绑定
	bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));

	udp_respon(sockfd);

	return 0;
}
客户端:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>

#define PORT 8888
#define MAX_SIZE 1024

void udp_request(int sockfd, const struct sockaddr_in *addr, int len)
{
	char buffer[MAX_SIZE];
	int n;

	while(1)
	{
		fgets(buffer, MAX_SIZE, stdin);
		//向目标端发送数据
		sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)addr, len);
		printf("I have sent to server %s", buffer);
		printf("Waiting respond from server\n");

		bzero(buffer, MAX_SIZE);
		
		//这里不需要了解数据发送端的信息,所以设置NULL
		n = recvfrom(sockfd, buffer, MAX_SIZE, 0, NULL, NULL);
		buffer[n] = 0;
		printf("I have received from server ");
		fputs(buffer, stdout);
		printf("\n");
	}
}

int main()
{
	int sockfd;
	struct sockaddr_in seraddr;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	//目标端套接口结构体设置
	bzero(&seraddr, sizeof(struct sockaddr_in));
	seraddr.sin_family = AF_INET;
	seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
	seraddr.sin_port = htons(PORT);

	udp_request(sockfd, &seraddr, sizeof(struct sockaddr_in));

	close(sockfd);
	return 0;
}
对于服务器程序而言,编程步骤:
调用 socket,创建一个不与任何网络连接相对应的套接口(socket),其返回值是一个文件描述符;调用 bind,将刚刚创建的 socket 与本机的 IP地址和端口号绑定,这样一来 socket 就变成了一个 3元组;调用 recvfrom,从套接口接收客户端发送过来的数据(同时能获得客户端的 IP地址和端口号),当然如果此时客户端并未发送数据,那么 recvfrom 将阻塞到有数据到达为止;根据客户端的要求进行数据处理;调用 sendto (将客户端 IP和端口号作为参数传入),向套接口写入处理后的数据,该数据将通过网络到达客户端,当所有数据都已处理完毕,将调用 close 关闭套接口,自此通信结束。
对于客户机程序而言,编程步骤:
调用 socket,创建一个不与任何网络连接相对应的套接口(socket),调用 sendto(将服务器 IP和端口号作为参数传入)向 socket 中写入数据,此时系统将选择一个本机尚未使用的端口号作为本地端口号,并选择本机的 IP地址作为本地 IP,这样,该 socket 就变成了一个 3元组,该数据将到达服务器,被 recvfrom 所读取(服务器端),然后调用
recvfrom(客户端),等待从 socket 获取服务器通过 sendto 回送的数据,当所有数据都接收完毕,调用 close 关闭套接口,自此通信结束。



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《UNIX网络编程(第三版)》是由W. Richard Stevens和Bill Fenner合著的一本经典著作。该书深入讲解了UNIX操作系统网络编程的相关知识和技巧,是学习UNIX网络编程的优秀资料。 这本书主要分为两部分,第一部分介绍了UNIX网络编程的基本概念和基础知识。作者从TCP/IP协议栈、套接字编程接口、进程间通信等基本概念入手,详细解析了UNIX网络编程的核心技术。此外,还介绍了UNIX操作系统网络编程的原理与实践,包括网络编程API、套接字选项、IO复用技术等。这部分内容全面详细,对于初学者来说很容易理解和上手。 第二部分则是实际应用方面的内容。作者通过具体的实例,深入探讨了UNIX网络编程在实际项目中的应用。包括网络连接、TCP和UDP服务器、多进程/多线程服务器、域名解析、广播和组播等。通过这些实例,读者可以更好地理解和运用UNIX网络编程的技术和方法。 《UNIX网络编程(第三版)》在内容上全面而深入,实用性强。这本书既适合初学者作为学习的入门教材,也适合有一定经验的开发人员作为手册和工具书。此外,该书的编写风格清晰简练,结构合理,配有大量实例和图示,有助于读者更好地理解和运用所学的知识。 总之,《UNIX网络编程(第三版)》是一本经典的UNIX网络编程指南,无论是对于初学者还是有经验的开发人员,都是一本不可多得的优秀参考书。阅读和学习该书的内容,不仅可以提升对UNIX网络编程的理解和应用水平,还能够为进一步深入学习和研究相关领域提供坚实的基础。 ### 回答2: 《UNIX网络编程 第三版》(英文版)是由W. Richard Stevens和Bill Fenner编著的一本网络编程方面的经典参考书籍。 该书深入讲解了UNIX操作系统下网络编程的各个方面,包括套接字编程、进程控制、线程编程、信号处理、I/O复用、套接字选项、多播、广播、多路复用器、非阻塞I/O、地址转换、名字和地址转换等等。此外,该书还介绍了UNIX系统的底层协议,如TCP/IP和UDP/IP,并详细解释了网络编程中的各种细节和技巧。 《UNIX网络编程 第三版》以其深入浅出的讲解风格和丰富的示例代码而闻名,每个章节都有大量的代码示例和案例,便于读者理解和实践。此外,书中还包含了大量的图表和图示,帮助读者更好地理解网络编程中的各个概念和过程。 此外,《UNIX网络编程 第三版》还包含了关于IPv6的内容,对IPv6进行了深入讲解和示例演示,使读者能够了解并应用最新的网络技术。 总之,这本书是一本非常权威和全面的UNIX网络编程参考书籍,不仅适合网络编程从业人员和学习者,也适用于正在进行网络编程项目的开发人员。无论是初学者还是有经验的专业人士,都可以从中获得不少的收获。如果你对UNIX网络编程感兴趣或需要进行相关开发,这本书是一本不可或缺的参考资料。 ### 回答3: 《UNIX网络编程 第三版》是由W. Richard Stevens和Bill Fenner共同编写的经典图书。这本书是Unix网络编程领域的权威和经典之作,被广泛认为是学习Unix系统编程和网络编程的指南。 这本书首先介绍了Unix网络编程的基本概念和原理,包括套接字、地址族、TCP/IP协议等。然后,它详细介绍了Unix网络编程的各个方面,包括套接字编程、多进程和多线程编程、I/O多路复用、UDP编程、域名解析等。 书中采用了清晰易懂的语言,配合大量的示例代码和图表,帮助读者理解和掌握Unix网络编程的核心概念和技术。它不仅注重理论知识的介绍,还强调实际应用和问题解决,为读者提供了大量实用的编程经验和技巧。 此外,第三版还新增了一些内容,如IPv6编程、高级I/O、Scoket选项、Socket超时、IP选项处理等,以适应当今互联网发展的需求。 总的来说,《UNIX网络编程 第三版》是Unix系统和网络编程领域的经典教材,不仅适合想要深入了解Unix网络编程的学生和开发人员,也是Unix系统管理员和网络工程师的必备参考书。它既具备理论性,又注重实践应用,可以帮助读者更好地理解和应用Unix网络编程技术,提高系统和网络的性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值