博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于UDP的服务器和客户端之间的通信
阅读量:7096 次
发布时间:2019-06-28

本文共 4229 字,大约阅读时间需要 14 分钟。

hot3.png

一、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范围的端口号已经被系统使用或保留。
sin_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是无连接的,面向数据报,不可靠的传输协议。

--------------------- 
作者:wuxinrenping 
来源:CSDN 
原文:https://blog.csdn.net/wuxinrenping/article/details/81026159 
版权声明:本文为博主原创文章,转载请附上博文链接!

转载于:https://my.oschina.net/u/3874841/blog/3021470

你可能感兴趣的文章
小米手机如期而至
查看>>
STM32 RCC实验 MCO脚输出时钟波形
查看>>
Flash 最小化,帧速变慢的问题
查看>>
java对redis的基本操作(一)
查看>>
基因组印记
查看>>
34个漂亮的应用程序后台管理界面(系列三)
查看>>
double free or corruption (!prev): 0x080644c8 ***
查看>>
在VMware上搭建iPhone开发环境(转)
查看>>
MongoCola使用教程 1 - MongoDB的基本操作和聚合功能
查看>>
2012年3月份30个优秀的jquery插件集合 功能强大
查看>>
公共的Json操作C#类
查看>>
WebService如何调试及测试工具
查看>>
HDU-2091 水题
查看>>
【转】条件编译#ifdef的妙用详解_透彻
查看>>
jQuery.autocomplete 支持中文输入
查看>>
配置ubuntu的mac主题
查看>>
makefile文件的两种常用书写格式(搜索路径式+递归式)
查看>>
Android4.0蓝牙使能的详细解析
查看>>
Freemarker常用技巧(三)
查看>>
Java Gradle入门指南之依赖管理(添加依赖、仓库、版本冲突) (转)
查看>>