Linux学习四:UDP编程(上)

时间:2022-08-07 15:42:44

关于UDP和TCP对比优缺,这里就不说了。
  使用UDP代码所掉用的函数和用于TCP的函数非常类似,这主要因为套接口库在底层的TCP和UDP的函数上加了一层抽象,通过这层抽象使得编程更容易,但失去了一些控制。
  二者函数调用唯一的实际区别是soceket函数调用的一个参数,TCP的是SOCK_STREAM,UDP的是SOCK_DGRAM,二者都可以使用recvfrom函数,而recv只用于TCP。
  当然函数的变化不是这么简单,因为你要从一种有连接的协议转向到无连接的协议上去。
这里写个很简单直接的UDP应用了解过程。实现一个启动向另一个系统的某个端口传输消息的程序,这个程序没有握手机制,也不确定另一个系统是否正在侦听、接受或处理数据。
  发送端:sender,发送文本消息,再发个终止消息(告诉接收方发送完毕)。

UDP编程的客户端一般步骤是:

1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
4、设置对方的IP地址和端口等属性;
5、发送数据,用函数sendto();
6、关闭网络连接;
  sender.c :
      #include “stdio.h”只能用“”表示了,<显示不出来

#include “stdlib.h”
      #include “string.h”
      #include “sys/socket.h”
      #include “netinet/in.h”
      #include “arpa/inet.h”
      #include “netdb.h”
  int port=6789;

void main()
         {
           int socket_descriptor;// 定义套接口描述字
           int i=0;
           char buf[120];//设置缓冲区
           struct sockaddr_in address;//处理网络通信地址,把像xxx.xxx.xxx.xxx十进制

//的IP地址转化 为32位整数,失败返回INADDR_NONE

初始化Internet协议套接字地址结构
           bzero(&address,sizeof(address));//空数据结构
           address.sin_family=AF_INET;
           address.sin_addr.s_addr=inet_addr("127.0.0.1");//设置服务器的ip地址函数

address.sin_port=htons(port);  //设置端口

创建一个UDP套接字
           socket_descriptor=socket(AF_INET,SOCK_SGRAM,0);

循环发送数据
           for(i=0;i<120;i++)
             {
               sprintf(buf,"data packet with ID %d\n",i);
               sendto(socket_descriptor,buf,sizeof(buf),0,
                           (struct sockaddr *)&address,sizeof(address));
             }

发送一个终止信息
              sprintf(buf,"stop\n");
           sendto(socket_descriptor,buf,sizeof(buf),0,
                       (struct sockaddr *)&address,sizeof(address));

关闭网络
           close(socket_descriptor);
           printf("Message Sent,Terminating\n");

exit(0);
         }
具体详细注释下:

首先库文件:

stdlib.h:包含了C、C++语言的最常用的系统函数,定义了五种类型、一些宏和通用工具函数.

常用的函数如malloc()、calloc()、realloc()、free()、ystem()、atoi()、atol()、rand()、

srand()、exit()等等

string.h:字符数组的函数定义的头文件,常用函数有strlen、strcmp、strcpy等等

sys/socket.h:提供socket函数及数据结构

netinet/in.h:定义数据结构sockaddr_in,互联网地址族

arpa/inet.h:提供IP地址转换函数

netdb.h:提供设置及获取域名的函数

再看看涉及到的函数:

struct sockaddr是通用的套接字地址,而struct sockaddr_in则是internet环境下套接字的地址形式,

二者长度一样都是16个字节。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。一般情况下,

需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。

inet_addr被linux下的inet_aton取代.函数作用是把作为参数的字符串转化为内部能够使用的一个

作为因特网地址的整数.

htons函数处理不同系统对内部的数据表示方法不同,使你的主机字节序和网络字节序匹配.

socket函数创建套接字:0表示默认 socket函数,向系统申请一个通信端口SOCK_DGRAM 默认使用UDP
                             调用socket函数时:

UDP使用SOCK_SGRAM,

TCPIP使用SOCK_STREAMA
                                                AF_INET表示IPV4.

AF_INET6表示IPV6
                                                AF_UNIX,AF_LOCAL表示本地通信
                                                SOCK_STREAM: 提供面向连接的稳定数据传输,即TCP协议。
                                             OOB: 在所有数据传送前必须使用connect()来建立连接状态。
                                                  SOCK_DGRAM: 使用不连续不可靠的数据包连接。
                                                      SOCK_SEQPACKET: 提供连续可靠的数据包连接。
                                                  SOCK_RAW: 提供原始网络协议存取。
                                                  SOCK_RDM: 提供可靠的数据包连接。
                                              SOCK_PACKET: 与网络驱动程序直接通信。

sendto函数通过套接口发送一个消息,在此使用了无连接的套接口:消息的发送目的地址由address指定。具体参数介绍不再说明。

sprintf函数把格式化的数据写入某个字符串,返回值:字符串长度(strlen)例如:

char* who = "I";
         char* whom = "csdn";
         sprintf(s, "%s love %s.", who, whom); //产生:"I love csdn. "  这字符串写到s中

  接收端:receiver

receiver.c:
        #include “stdio.h”只能用“”表示了,<显示不出来

#include “stdlib.h”
      #include “string.h”
      #include “sys/socket.h”
      #include “netinet/in.h”
      #include “arpa/inet.h”
      #include “netdb.h”
        int port=6789;
        void main()
         {
           int sin_len;
           char message[256];
           int socket_descriptor;
           struct sockaddr_in sin;
           printf("Waiting for data from sender\n");
          
           bzero(&sin,sizeof(sin));
           sin.sin_family=AF_INET;
           sin.sin_addr.s_addr=htonl(INADDR_ANY);//htonl(将32位主机字符顺序

//转换成网络字符顺序)
           sin.sin_port=htons(port);//htons(将16位主机字符顺序转换成网络字符

//顺 序)
           sin_len=sizeof(sin);
 
           socket_descriptor=socket(AF_INET,SOCK_DGRAM,0);//建立一个端口
           bind(socket_descriptor,(struct sockaddr *)&sin,sizeof(sin));//将主机地址

//与端口绑定
           while(1)
              {
                 recvfrom(socket_descriptor,message,sizeof(message),0,
                                (struct sockaddr *)&sin,&sin_len);//接受消息
                 printf("Response from server:%s\n",message);
                 if(strnmcp(message,"stop",4)==0)//比较接受message和stop的前4个

//字符。>返回大于1,=返回0。

{
                      printf("Sender has told me end connection\n");
                      break;
                     }
              }
            close(socket_descriptor);
            exit(0);
         }
分别:gcc -o xxx xxx.c  注意:o是小写,大写的话会提示没有xxx文件或文件夹。
然后分别在不同工作台运行:./xxx
显示如下:
Linux学习四:UDP编程(上)

Linux学习四:UDP编程(上)