基于UDP的服务器和客户端之间的通信

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wuxinrenping/article/details/81026159

一、socket 网络套接字

创建
函数原型:
int socket(int  domain, int  type, int  protocol);
参数说明:  
domain:协议域,又称协议族(family)。常用的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域Socket)、AF_ROUTE等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
type:指定Socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。流式Socket(SOCK_STREAM)是一种面向连接的Socket,针对于面向连接的TCP服务应用。数据报式Socket(SOCK_DGRAM)是一种无连接的Socket,对应于无连接的 UDP服务应用。
protocol:指定协议。常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
注意:1.type和protocol不可以随意组合,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当第三个参数为0时,会自动选择第二个参数类型对应的默认协议。
2.WindowsSocket下 protocol参数中不存在IPPROTO_STCP
二、sockaddr_in 
sockaddr_in(在netinet/in.h中定义):
1
2
3
4
5
6
7
8
9
10
11
12
13
struct  sockaddr_in
 
{
 
short  sin_family; /*Address family一般来说AF_INET(地址族)PF_INET(协议族)*/
 
unsigned  short  sin_port; /*Port number(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/
 
struct  in_addr sin_addr; /*IP address in network byte order(Internet address)*/
 
unsigned  char  sin_zero[8]; /*Same size as struct sockaddr没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐*/
 
};
in_addr结构
1
2
3
4
5
typedef  uint32_t in_addr_t;
struct  in_addr
   {
     in_addr_t s_addr;
   };
sin_family指代协议族,在socket编程中只能是AF_INET
sin_port存储 端口号(使用网络 字节顺序),在linux下,端口号的范围0~65535,同时0~1024范围的端口号已经被系统使用或保留。
s in_addr存储IP地址,使用in_addr这个数据结构
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
s_addr按照网络字节顺序存储IP地址

三、绑定

int bind(SOCKET  socket, const struct sockaddr*  address, socklen_t  address_len);
参数说明:
socket:是一个 套接字描述符。
address:是一个sockaddr结构 指针,该结构中包含了要结合的地址和 端口号
address_len:确定address 缓冲区的长度。
返回值:
如果函数执行成功,返回值为0,否则为SOCKET_ERROR。

四、接收

函数原型:
ssize_t recvfrom(int  sockfd, void  buf, int  len, unsigned int  flags, struct socketaddr*  from, socket_t*  fromlen);
参数说明:
sockfd:标识一个已连接 套接口的描述字。
buf:接收 数据缓冲区
len:缓冲区长度。
flags:调用操作方式。是以下一个或者多个标志的组合体,可通过or操作连在一起:
from:(可选) 指针,指向装有源地址的缓冲区。
fromlen:(可选)指针,指向from缓冲区长度值。

五、发送

函数原型:
int sendto( SOCKET  s, const char FAR*  buf, int  size, int  flags, const struct sockaddr FAR*  to, int  tolen);
参数说明:
s套接字
buf:待发送数据的缓冲区
size:缓冲区长度
flags:调用方式标志位, 一般为0, 改变Flags,将会改变Sendto发送的形式
addr:(可选) 指针,指向目的套接字的地址
tolen:addr所指地址的长度
返回值:
如果成功,则返回发送的字节数,失败则返回SOCKET_ERROR。

服务器端代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int main(int argc,char *argv[])
{
        if(argc!=3)
        {
                printf("Usage ./server [ip]  [port]\n");
                return 1;
        }
        int sock=socket(AF_INET,SOCK_DGRAM,0);
        if(sock<0)
        {
                perror("socket");
                return 2;
        }

        struct sockaddr_in local;

 local.sin_family=AF_INET;//ipv4
        local.sin_port=htons(atoi(argv[2]));//主机字节序转换为网络字节序
        local.sin_addr.s_addr=inet_addr(argv[1]);//字符串转in_addr的函数


        if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
        {
                perror("bind");
                return 3;
        }


        char buf[1024];
        struct sockaddr_in client;
        while(1)
        {
                socklen_t len=sizeof(client);
                ssize_t s=recvfrom(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&client,&len);
                if(s>0)
                {
                        buf[s]=0;

                        printf("[%s:%d]:%s\n",inet_ntoa(client.sin_addr),\

   ntohs(client.sin_port),buf);
                        sendto(sock,buf,strlen(buf),0, \
                                        (struct sockaddr*)&client,sizeof(client));
                }
        }
        close(sock);
        return 0;
}

客户端的代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int main(int argc,char *argv[])
{
        if(argc!=3)
        {
           printf("./Usage [ip] [port]\n");
           return 1;
        }
        int sock=socket(AF_INET,SOCK_DGRAM,0);
        if(sock<0)
        {
                perror("socket");
                return 2;

        }

struct sockaddr_in server;
        server.sin_family=AF_INET;
        server.sin_port=htons(atoi(argv[2]));
        server.sin_addr.s_addr=inet_addr(argv[1]);


        char buf[1024];
        struct sockaddr_in peer;
        while(1)
        {
                socklen_t len=sizeof(peer);
                printf("Please Enter# ");
                fflush(stdout);
                ssize_t s=read(0,buf,sizeof(buf)-1);
                if(s>0)
                {
                        buf[s-1]=0;
                        sendto(sock,buf,strlen(buf),0,\
                                        (struct sockaddr*)&server,sizeof(server));
                        ssize_t _s=recvfrom(sock,buf,sizeof(buf)-1,0,\
                                        (struct sockaddr*)&peer,&len);

         if(_s>0)
                        {
                                buf[_s]=0;
                                printf("server echo# %s\n",buf);
                        }
                }
        }
        close(sock);
        return 0;

}

UDP是无连接的,面向数据报,不可靠的传输协议。                                     

猜你喜欢

转载自blog.csdn.net/wuxinrenping/article/details/81026159