这篇博客的目的是想实现一个简单的UDP服务器程序,完成客户端与服务器端的通信。
因为涉及的小知识点比较多,所以本篇博客的篇幅较长,但是会讲的很详细
在下一篇博客里,我会总结Linux中用socket实现TCP网络程序
在这里插入图片描述
1.程序的第一步是创建套接字(socket)

#include<sys/socket.h>	//头文件
//创建套接字函数,socket
int socket(int domain, int type, int protocol);
//domain:地址域,常用的有以下两种
//	AF_INET             IPv4 Internet protocols          ip(7)   
// 	AF_INET6            IPv6 Internet protocols          ipv6(7)
//type:套接字类型,常用的有以下两种
//	 SOCK_STREAM    流式套接字   
//	 SOCK_DGRAM    数据报套接字
//protocol:协议类型
//	默认为0,流式套接字默认TCP协议,数据包套接字默认UDP协议
//	在这里我们直接用UDP协议,即 IPPROTO_UDP	
//返回值:int型,成功返回套接字描述符,失败返回-1

2.程序的第二步是为套接字绑定地址信息,确定socket能够操作缓冲区。
首先我们要提到一个网络地址结构体,sockaddr_in.

struct sockaddr_in {    
	sa_family_t    sin_family; /*协议类型: AF_INET */   
	 in_port_t      sin_port;   /* 网络字节序 */    
 	struct in_addr sin_addr;   /*网络地址*/
};

然后就是为套接字绑定地址信息的函数,bind.

#include<sys/socket.h>	//头文件
 int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);    
//	sockfd:套接字描述符   
//	addr:要绑定的地址信息    
//	addrlen:地址信息的长度
//	返回值:int型,成功返回0,失败返回-1

3.程序的第三步是接收数据

#include<sys/type.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:用于存储接受的数据,把数据拷贝到buf当中
//	len:想要接受的数据长度
//	flags:默认为0,如果缓冲区没有数据,就阻塞等待直到有数据并拷贝完毕
//	src_addr:用于确定数据是哪一个客户端发送的,即确定发送端的地址信息
//	addrlen:发送端地址信息的长度,不能为0
//	返回值:ssize_t类型,	成功返回实际接收数据的长度,失败返回-1

4.程序的第四步是发送数据

#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:socket描述符,发送数据的时候就是通过这个socket所绑定的地址来发送
//	buf:要发送的数据
//	len:	要发送数据的长度
//	flags:0-默认阻塞式发送
//	dest_addr:数据要发送的目的地址,对端地址
//	addrlen:地址信息长度
//	返回值:ssize_t类型,返回实际发送的数据长度,失败返回-1

5.程序的第五步是关闭socket,即close(sockfd)
上面五个步骤是服务器端的步骤,客户端的步骤类似,我不做讲解,下面我把代码分享给大家。
服务器端:udp_client.c

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<errno.h>
  5 #include<string.h>
  6 #include<sys/socket.h>
  7 #include<netinet/in.h>
  8 #include<arpa/inet.h>
  9 
 10 int main()
 11 {
 12         int sockfd=socket(AF_INET,SOCK_DGRAM,0);
 13         if(sockfd<0)
 14         {
 15                 perror("socket error\n");
 16                 return -1;
 17         }
 18         struct sockaddr_in server;
 19         server.sin_family = AF_INET;
 20         server.sin_port=htons(9000);
 21         server.sin_addr.s_addr=inet_addr("192.168.1.104");
 22 
 23         char buff[1024]={0};
 24         struct sockaddr_in peer;
 25         while(1)
 26         {
 27                 socklen_t len=sizeof(peer);
 28                 printf("please enter:");
 29                 fflush(stdout);
 30                 ssize_t s=read(0,buff,sizeof(buff)-1);
 31                 if(s>0)
 32                 {
 33                         buff[s-1]=0;
 34                         sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&server,sizeof(server));
 35                         ssize_t _s=recvfrom(sockfd,buff,sizeof(buff)-1,0,(struct sockaddr*)&peer,&len);
 36                         if(_s>0)
 37                         {
 38                                 buff[_s]=0;
 39                                 printf("Server echo#%s\n",buff);
 40                         }
 41                 }
 42         }
 43 
 44 
 45         return 0;
 46 }

客户端:udp_server.c

 1 //这是一个非常简单的udp服务端程序
  2 //功能是:客户端与服务端的聊天程序
  3 
  4 #include<stdio.h>
  5 #include<unistd.h>
  6 #include <sys/socket.h>
  7 #include<errno.h>
  8 #include<string.h>
  9 #include<netinet/in.h>
 10 #include<arpa/inet.h>
 11 #include<stdlib.h>
 12 
 13 int main()
 14 {
 15         //1.创建套接字
 16         //int socket(int domain, int type, int protocol);
 17         int sockfd =socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
 18         if(sockfd <0)
 19         {
 20                 perror("socket error\n");
 21                 return -1;
 22         }
 23         //2.为套接字绑定地址信息
 24         //  int bind(int sockfd, const struct sockaddr *addr,
 25         //                  socklen_t addrlen)
 26         struct sockaddr_in addr;
 27         addr.sin_family=AF_INET;
 28         addr.sin_port=htons(9000);
 29         addr.sin_addr.s_addr=inet_addr("192.168.1.104");
 30         socklen_t addrlen =sizeof(struct sockaddr_in);
 31         int ret=bind(sockfd,(struct sockaddr*)&addr,addrlen);
 32         if(ret<0)
 33         {
 34                 perror("bind error\n");
 35                 close(sockfd);
 36                 return -1;
 37         }
 38         //3.接收数据
 39         // ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
 40         //                         struct sockaddr *src_addr, socklen_t *addrlen);
 41         //      sockfd: socket描述符
 42         //      buf:   用于将存储接收的数据
 43         //      len:   想要接收的数据长度
 44         //      flags: 0-默认是说如果缓冲区没有数据,那么我就阻塞等待
 45         //      src_addr:  用于确定数据的发送端地址信息
 46         //      addrlen:   地址信息的长度
 47         //      返回值:实际接收的数据长度 ,-1:失败
 48         while(1)
 49         {
 50                 //接收数据
 51                 char buff[1024]={0};
 52                 struct sockaddr_in cli_addr;
 53                 addrlen=sizeof(struct sockaddr_in);
 54                 ssize_t rlen=recvfrom(sockfd,buff,1023,0,(struct sockaddr*)&cli_addr,&addrlen);
 55                 if(rlen<0)
 56                 {
 57                         perror("recvfrom error\n");
 58                         close(sockfd);
 59                         return -1;
 60                 }
61                 //inet_ntoa:将网络地址转换成“.”点隔的字符串格式
 62                 //ntohs:将网络字节序转成端口字节序。
 63                 printf("client[%s:%d] say:%s\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port),buff);
 64                 //发送数据
 65                 //ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
 66                 //                      const struct sockaddr *dest_addr, socklen_t addrlen);
 67                 //sockfd:socket描述符,发送数据的时候就是通过这个socket所绑定的地址来发送。
 68                 //buf:要发送的数据
 69                 //len:要发送数据的长度
 70                 //flag:0-默认阻塞式发送
 71                 //dest_addr:数据要发送到的对端地址,目的地址
 72                 //addrlen:地址信息长度
 73                 //返回值:返回时记得发送长度,失败返回-1/ 
 74                 memset(buff,0x00,1024);//将数组初始化为0
 75                 printf("server say:");
 76                 scanf("%s",buff);
 77                 sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&cli_addr,addrlen);
 78 
 79         }
 80         close(sockfd);
 81         return 0;
 82 }

运行结果:
在这里插入图片描述
在这里插入图片描述

Logo

更多推荐