C 基于UDP实现一个简易的聊天室
引言
本文是围绕Linux udp api 构建一个简易的多人聊天室.重点看思路,帮助我们加深
对udp开发中一些api了解.相对而言udp socket开发相比tcp socket开发注意的细节要少很多.
但是水也很深. 本文就当是一个demo整合帮助开发者回顾和继续了解 linux udp开发的基本流程.
首先我们来看看 linux udp 和 tcp的异同.
/* 这里简单比较一下TCP和UDP在编程实现上的一些区别: TCP流程 建立一个TCP连接需要三次握手,而断开一个TCP则需要四个分节。当某个应用进程调用close(主动端)后
(可以是服务器端,也可以是客户 端),这一端的TCP发送一个FIN,表示数据发送完毕;另一端(被动端)发送一
个确认,当被动端待处理的应用进程都处理完毕后,发送一个FIN到主动端,并关闭套接口,主动端接收到这个
FIN后再发送一个确认,到此为止这个TCP连接被断开。 UDP套接口 UDP套接口是无连接的、不可靠的数据报协议;既然他不可靠为什么还要用呢?
其一:当应用程序使用广播或多播是只能使用UDP协议;
其二:由于它是无连接的,所以速度快。因为UDP套接口是无连接的,如果一方的数据报丢失,那另一方将无
限等待,解决办法是设置一个超时。在编写UDP套接口程序时,有几点要注意:建立套接口时socket函
数的第二个参数应该是SOCK_DGRAM,说明是建立一个UDP套接口;由于UDP是无连接的,所以服务器端
并不需要listen或accept函数;当UDP套接口调用connect函数时,内核只记录连接放的IP地址 和端
口,并立即返回给调用进程. */
参照
linux udp api简介 http://blog.****.net/wocjj/article/details/8315559
tcp 和udp区别 http://www.cnblogs.com/Jessy/p/3536163.html
这里简单引述一下 udp相比tcp 用到的两个api . recvfrom()/sendto() 具体细节如下
#include <sys/types.h> #include <sys/socket.h> /* * 这两个函数基本等同于 一个 send 和 recv . 详细参数解释如下 * s : 文件描述符,等同于 socket返回的值 * buf : 数据其实地址 * len : 发送数据长度或接受数据缓冲区最大长度 * flags : 发送标识,默认就用O.带外数据使用 MSG_OOB, 偷窥用MSG_PEEK ..... * addr : 发送的网络地址或接收的网络地址 * alen : sento标识地址长度做输入参数, recvfrom表示输入和输出参数.可以为NULL此时addr也要为NULL * : 返回0表示执行成功,否则返回<0 . 更多细节查询man手册 */ extern int sendto (int s, const void *buf, int len, unsigned int flags, const struct sockaddr *addr, int alen); extern int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *addr, int *alen);
上面就是两个函数的大致用法. 具体可以查看linux api帮助手册. 最好就用 man sendto / man recvfrom 把那一系列函数都看看.
现在很多文章都是转载,但是找不见转载的地址, 下面会举一个简易的UDP回显服务器的demo加深理解.
前言
首先看设计图
有点low. 简单看看吧. 那我们先看 客户端代码 udpclt.c 代码
#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #define _SHORT_PORT (8088) // // udp client heoo // int main(int argc, char * argv[]) { int fd, len; struct sockaddr_in ar = { AF_INET }; socklen_t al = sizeof (struct sockaddr_in); char msg[BUFSIZ] = ":) 谁也不会喜欢工作狂 ~"; // 创建 client socket if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { perror("main socket dgram"); exit(EXIT_FAILURE); } ar.sin_port = htons(_SHORT_PORT); // 开始发送消息包到服务器, 默认走 INADDR_ANY sendto(fd, msg, sizeof msg - 1, 0, (struct sockaddr *)&ar, al); // 开始接收服务器回过来的报文 len = recvfrom(fd, msg, sizeof msg - 1, 0, (struct sockaddr *)&ar, &al); if (len == -1) { perror("main recvfrom"); exit(EXIT_FAILURE); } msg[len] = '