UDP的C/S架构

C/S框架

客户端/服务器框架

优点:本地可以缓存,应用层协议可以灵活制定

缺点:开发工作量大,安全性不高

UDP协议

用户数据协议,与TCP一样都属于传输层协议。

UDP特点

无连接,不保证数据可靠,可能失序,传输效率快,一般用于数据高效的应用(如:直播、视频等)。

 UDP服务器创建流程

1.创建套接字

int socket(int domain, int type, int protocol);

{
    domain:指定通信域;这将选择用于通信的协议族。一般选择AF_INET (IPv4)  、AF_INET6(IPv6)  ;

     type: 指定的类型,该类型指定通信语义。一般使用SOCK_STREAM(流式套接字,适用于TCP)、SOCK_DGRAM(数据报套接字,一般适用于UDP)、 SOCK_RAW(原始套接字);

     protocol:指定套接字类型,与  type确定选用的类型 , 0:默认type选取的类型。

}
 

2.绑定套接字

 struct sockaddr_in {
               sa_family_t    sin_family; /* 通信协议族: AF_INET */
               in_port_t      sin_port;   /* 设置端口 */
               struct in_addr sin_addr;   
           };


           struct in_addr {
               uint32_t       s_addr;     /* 设置IP地址 */
           };

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

{
      sockfd:通信套接字

      addr:(struct sockaddr_in*)结构体地址,类型不一样,需要强转

      addrlen:(struct sockaddr_in *)结构体大小

}

 这里为什么要用struct sockaddr_in,而不是直接用struct sockaddr?

因为struct sockaddr中sa_data把目标地址和端口信息混在了一起,而sockaddr_in解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中,所以为了方便直接用struct sockaddr_in,用时强转一下就可以了。

struct sockaddr {
               sa_family_t sa_family;
               char        sa_data[14];
           }

 3.数据接收/发送

//接收

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

//发送

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

{

        sockfd:绑定套接字

        buf:传输接/发地址

        len:传输大小

        flags:传输状态,0:堵塞状态;MSG_DONTWAIT:非堵塞状态

        src_addr:接收/发送方IP和端口的结构体地址

        addrlen:结构体大小

}

4.关闭套接字

 int close(int fd);

{

        fd:创建的套接字

}

//回收资源,避免占用内存

 UDP客户端创建流程

 1.创建套接字

int socket(int domain, int type, int protocol);

{
    domain:指定通信域;这将选择用于通信的协议族。一般选择AF_INET (IPv4)  、AF_INET6(IPv6)  ;

     type: 指定的类型,该类型指定通信语义。一般使用SOCK_STREAM(流式套接字,适用于TCP)、SOCK_DGRAM(数据报套接字,一般适用于UDP)、 SOCK_RAW(原始套接字);

     protocol:指定套接字类型,与  type确定选用的类型 , 0:默认type选取的类型。

}

 2.数据接收/发送

 

//接收

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

//发送

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

{

        sockfd:绑定套接字

        buf:传输接/发地址

        len:传输大小

        flags:传输状态,0:堵塞状态;MSG_DONTWAIT:非堵塞状态

        src_addr:接收/发送方IP和端口的结构体地址

        addrlen:结构体大小

}

3.关闭套接字 

  int close(int fd);

服务器 udp_sever.c

#include 
#include 
#include 
#include 
#include 
#include  
#include 
#include 
#include 

#define SIZE 128
#define PERROR(msg) do{perror(msg);exit(-1);}while(0)
int main(int argc,char *argv[])
{
	int sockfd = socket(AF_INET,SOCK_DGRAM,0);    //创建套接字
	if(sockfd < 0)
	PERROR("socket");
	
	struct sockaddr_in udp_sever,udp_client;        //定义结构体
	udp_sever.sin_family = AF_INET;                 //选择协议
	udp_sever.sin_port = htons(8989);                //绑定端口
	udp_sever.sin_addr.s_addr = inet_addr("0.0.0.0");    //自动匹配可用IP

	if(bind(sockfd,(struct sockaddr *)&udp_sever,sizeof(udp_sever)) < 0)    //绑定套接字
		PERROR("bind");

	char buf[SIZE] = {0};
	memset(&udp_client,0,sizeof(udp_client));        //清0
	int cli_len = sizeof(udp_client);

	while(1)
	{
		memset(buf,0,sizeof(buf));
		recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&udp_client,&cli_len);
        //接收客户端发送的
		
        printf("<%s>##<%d>\n%s\n",inet_ntoa(udp_client.sin_addr),ntohs(udp_client.sin_port),buf);
		memset(buf,0,sizeof(buf));

		sendto(sockfd,"xka",4,0,(struct sockaddr *)&udp_client,sizeof(udp_client));
        //发送信息给客户端

	}
	
	close(sockfd);        //关闭套接字
	return 0;
}

客户端upd_client.c

 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SIZE 128
#define PERROR(msg) do{perror(msg);exit(-1);}while(0)
int main(int argc,char *argv[])
{
	if(argc < 3)
	{
		fprintf(stderr,"Usage%s",argv[0]);        //键盘输入IP和端口
		return -1;
	}
        int sockfd = socket(AF_INET,SOCK_DGRAM,0);        //创建套接字
        if(sockfd < 0)
        PERROR("socket");

	struct sockaddr_in udp_sever;                         
	udp_sever.sin_family = AF_INET;                        //选择协议
	udp_sever.sin_port = htons(atoi(argv[2]));             //选择端口
	udp_sever.sin_addr.s_addr = inet_addr(argv[1]);        //选择IP

	char buf[SIZE] = {0};
	while(1)
	{
		fgets(buf,sizeof(buf),stdin);                    //键盘输入字符串
		buf[strlen(buf)-1]= '\0';                        //解决fgets自带的\n
		if(strncmp(buf,"quit",4) == 0)                   //quit退出
			break;
		sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&udp_sever,sizeof(udp_sever));
        //发送信息给服务器
		memset(buf,0,sizeof(buf));                        //清0 
		int sev_len = sizeof(udp_sever);
		recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&udp_sever,&sev_len);
        //接收服务器发送的信息
	    printf("recv from sev:%s\n",buf);
	}
	return 0;
}

 编译结果

 1@ubuntu:~/udp$ ./sev
<192.168.47.61>##<52289>
hello
<192.168.47.61>##<52289>
I am client

 1@ubuntu:~/udp$ ./cli 192.168.47.61 8989
hello
recv from sev:xka
I am client
recv from sev:xka
quit

你可能感兴趣的:(udp,服务器,网络,c#,网络协议)