Linux C基于UDP的网络编程

套接字(socket)

socket是一种可以进行网络通信的内核对象,它有一个唯一的标识符,一般称它为socket描述符——sockfd,可类比于文件描述符fd,基于Linux下一切皆文件的概念,所以sockfd也可以用read/write/close操作。


socket函数:创建socket对象
int socket(int domain, int type, int protocol);
  • domain:通信地址类型
      AF_UNIX/AF_LOCAL:本地进程间通信
      AF_INET:使用ipv4地址通信
      AF_INET6:使用ipv6地址通信

  • type:socket对象类型
    SOCK_STREAM:数据流协议,TCP(面向连接的通信协议)。特点是安全可靠,数据不会丢失,但速度慢。常用于安全性较高的场景;
    SOCK_DGRAM:数据报协议,UDP(面向无连接的通信协议)。特点是速度快,数据可能丢失,安全性和可靠性与tcp相比不同。一般用于安全性要求不高但是对速度有要求的场景。

  • protocol:特殊协议
      较少使用,一般直接写0

  • 返回值:成功返回非负描述符,失败返回-1

网络通信地址
struct sockaddr_in
  {
   // 通信地址类型
   short int sin_family;
   // 端口号
   in_port_t sin_port;
   // ip地址
   struct in_addr sin_addr;
  }

bind函数:把socket对象与通信地址建立联系
 int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
  • sockfd:socket对象的描述符,即socket函数的返回值
  • struct sockaddr* addr指定了想要绑定的ip和端口号,均用网络字节序-即大端模式;
  • addrlen是前面struct sockaddr(与sockaddr_in等价)的长度
  • 返回值: 成功返回0,失败返回-1

connect函数:连接通信目标
 int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

  • 个人计算机系统数据的存储方式可能是大端,也可能是小端,网络通信时需要的是大端数据,必须把数据转换成大端。
uint32_t htonl(uint32_t hostlong);//功能:把32位的主机字节序转换成32位网络字节序
 uint16_t htons(uint16_t hostshort);//功能:把16位的主机字节序转换成16位网络字节序
 uint32_t ntohl(uint32_t netlong);//功能:把32位网络字节序转换成32位的主机字节序
uint16_t ntohs(uint16_t netshort);//功能:把16位网络字节序转换成16位的主机字节序

生成端口号:
  • 端口号就是一个16位的无符整数(0~65536),一般设置为大于1024的值,1~1023为保留端口号。
  • 通常使用htons()函数来获取端口号。

生成ip地址:
  • 功能:把点分十进制的字符串ip地址转换成32位的无符号整数
in_addr_t inet_addr(const char *cp);
  • 功能:把32的的网络字节序的ip地址转换成点分十进制的字符串ip地址。
char *inet_ntoa(struct in_addr in);

recvfrom函数:接收数据并获取发送端的地址
 ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
  • buf:数据缓冲区
  • len:缓冲区的大小
  • flag:通常为0
  • src_addr:数据来源端的地址
  • *addrlen:src_addr的长度

sendto函数:发送数据到指定的目标
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
  • dest_addr:数据要发送的目标地址

UDP编程模型:

进程A:创建socket对象->准备地址->绑定->接收数据和来源的地址->原路返回数据->关闭socket。
进程B:创建socket对象->准备地址->向目标发送数据->接收数据->关闭socket。

使用udp协议实现双向传输数据(通过ip地址和端口,既可以与自己也可以与别人通信)。实现代码

UDP双向通信,先接收端
#include 
#include 
#include 
#include 
#include 
#include 

typedef struct sockaddr* saddrp;

int main(int argc, char const *argv[])
{
     //创建socket
     int sockfd = socket(AF_INET,SOCK_DGRAM,0);
     if (0 > sockfd)
     {
          perror("sockfd");
          return -1;
     }
     //准备地址
     struct sockaddr_in addr = {};
     addr.sin_family = AF_INET;//ipv4
     addr.sin_port = htons(5577);//端口号
     addr.sin_addr.s_addr = inet_addr("192.168.2.177");//我的ip地址
     //绑定
     int ret = bind(sockfd,(saddrp)&addr,sizeof(addr));
     if (0 > ret)
     {
          perror("bind");
          return -1;
     }
     struct sockaddr_in src_addr ={};
     socklen_t addr_len = sizeof(struct sockaddr_in);
     while(1)
     {
          char buf[255] = {};
          //接收数据和来源的ip地址
          recvfrom(sockfd,buf,sizeof(buf),0,(saddrp)&src_addr,&addr_len);
          printf("Recv:%s\n",buf);
          if (0 == strcmp(buf,"q")) break;
          //发送数据给目标地址
          printf("Please input the return value:");
          gets(buf);
          sendto(sockfd,buf,strlen(buf)+1,0,(saddrp)&src_addr,addr_len);
          if (0 == strcmp(buf,"q")) break;
     }  
     //关闭socket对象
     close(sockfd);
     return 0;
}
UDP实现代码 先发送端
#include 
#include 
#include 
#include 
#include 
#include 
typedef struct sockaddr* saddrp;

int main(int argc, char const *argv[])
{
     int sockfd = socket(AF_INET,SOCK_DGRAM,0);
     if (0 > sockfd)
     {
          perror("socket");
          return -1;
     }
     struct sockaddr_in addr = {};
     addr.sin_family = AF_INET;
     addr.sin_port = htons(5577);
     addr.sin_addr.s_addr = inet_addr("192.168.2.177");

     socklen_t addr_len = sizeof(struct sockaddr_in);
     while(1)
     {
          char buf[255] = {};
          printf("Plz input data:");
          gets(buf);
          sendto(sockfd,buf,strlen(buf)+1,0,(saddrp)&addr,sizeof(addr));
          if(0 == strcmp(buf,"q")) break;

          recvfrom(sockfd,buf,sizeof(buf),0,(saddrp)&addr,&addr_len);
          printf("Recv:%s\n",buf);
          if(0 == strcmp(buf,"q")) break;

     }
     close(sockfd);
     return 0;
}

返回网络通信

你可能感兴趣的:(Linux)