Liunx 套接字编程(1)UDP协议的操作且实现一个UDP通信客户端

1.套接字编程

主要讲解的就是如何编写一个网络通信程序

1.网络通信的数据中都会包含一个完整的五元组: sip,sport,dip,dport,protocol(源端IP,源端端口,对端IP,对端端口,协议)

五元组完整的描述了数据从哪来,到哪去,用的是什么数据格式。

2.网络通信,通常讨论的是两个主机进程之间的通信:客户端&服务端

客户端网络通信程序:通常指的是用户使用的一端

服务端网络通信程序: 通常指的是网络应用提供商提供服务的一端程序

客户端永远都是首先发起请求的一端(因为服务端是不知道客户端地址的(动态地址分配技术--谁上网给谁分配地址)

但是网络应用服务提供商,开发的客户端程序中都写入了服务器端的地址和端口,因此客户端是知道服务端地址的。还有一种原因就是,只有客户发送了请求,服务端才能提供对应的服务

2.TCP和UDP协议

套接字:socket的翻译,通常表示的是系统提供给程序员实现网络通信的一套接口

因此套接字编程学习的其实就是套接字接口的使用,通过这套接口完成网络通信程序的开发我们所讲解的套接字编程,主要是两个协议的通信程序编写: 传输层的TCP和UDP协议

TCP协议和UDP协议的区别:

联系:都是传输层协议

tcp协议: 传输控制协议--提供的是面向连接,可靠,基于字节流的数据传输

面向连接:通信前先要确定双方是否具有数据收发的能力

可靠传输:通过大量的一些控制机制,保证数据能够安全(有序且完整,一致)到达对端

字节流:没有传输大小限制,传输比较灵活的一种传输方式

tcp适用于安全要求大于实时要求的场景,比如文件传输

udp协议: 用户数据报协议--提供的是无连接,不可靠,基于数据包的数据传输

无连接:需要建立连接,只要知道对方的地址,就可以直接发送数据

不可靠:只要数据发送出去了就行,不管是否能够到达对端

数据报:有最大大小限制,且传输交付有大小限制的一种传输方式

因为没有大量的控制机制,因此传输速度快,因此适用于实时性要求大于安全性要求的场景,比如视频传输,音频传输

3.UDP协议

UDP协议通信程序的编写

UDP通信两端流程:

A.操作接口

  1. 创建套接字

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

2.为套接字绑定地址信息

int bind(int sockfd,  struct sockaddr*addr, socklen_len);

sockfd : socket返回的套接字描述符

addr: 要绑定的地址信息(不同地址域类型,有不同的地址结构)

因此IPv4通信定义 struct socketadddr_in结构即可

进行bind的时候,进行类型强转,这样可以实现一个接口绑定多种不同的地址结构

返回值:成功返回0, 失败返回-1

bind接口为套接字绑定的地址:

使用ifconfig指令绑定地址

推荐绑定10000以上

3.发送数据

ssize_t sendto(int sockfd, void* buf, size_t dlen, int flag, struct sockaddr* peer, socklen_t alen);

peer设置的谁,就发给谁

4.接收数据

ssize_t recvfrom(int sockfd, void* buf, size_t dlen, int flag, struct sockaddr* peer, socklen_t *alen)

凡是涉及到获取地址信息的操作,地址信息长度基本都是 socklen_t*

peer用于获取地址信息,peer中存的是谁,数据就是谁发给我的,peer这个参数在recvfrom这函数中设置的

返回值:成功返回实际接收到的数据长度,失败返回-1

5.关闭套接字,释放资源

int close(int fd);

B.字节序相关接口

下面这个几个接口已经进行了主机字节序的判断,不需要担心自己的主机字节序

代码实现、逐步注释

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main(int argc, char *argv[])
{
//下面几行,要求程序运行需要输入两个参数,一个为IP地址,一个为端口,加上程序命令本身,共三个参数,argc就表示参数,不等于3就给你提示,需要输入的东西 
    if(argc != 3)
    {
        printf("./udp_srv 192.168.2.2 9000\n");
        return -1;
    }
    uint16_t port = atoi(argv[2]);//atoi为字符串转数字,就是9000转赋值port
    char *ip =arg[1];//就是地址192.168.2.2

//1.创建套接字
//AF_INET为IPV4地址域类型,SOCK_DGRAM数据报套接字类型--提供数据报传输服务,
//IPPROTO_UDP--表示使用UDP协议
    int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sockfd < 0)
    {
        perror("socket error");
        retrun -1;
    }

//2.为套接字绑定地址信息
    struct sockaddr_in addr;//定义一个ipv4的地址结构出来
        addr.sin_family = AF_INET;//保存地址域类型
        addr.sin_port = htons(port);//一定要用htons,不能用htonl,保存网络字节序端口
        addr.sin_addr.s_addr = inet_addr(ip);//网络字节序的IP地址
    socklen_t len = sizeof(struct sockaddr_in);

    bind(sockfd, (struct sockaddr*)&addr, len);
    if(ret == -1)
    {
        perror("bind error");
        return -1;
     }

//3.循环接收发送数据
while(1)
{
    //接收数据
    char buf[1024] = {0};
    struct sockaddr_in peer;
    socklen_t len = sizeof(struct sockaddr_in);
    //注意,peer中的地址信息是系统设置的,数据是发的就设置谁的地址
    ssize_t ret = recvfrom(sockfd, buf, 1023, 0, (struct sockaddr*)&peer, &len);
    //recvfrom不但接收数据,还会获取这个数据是谁发送的,也即是对端地址信息
    if(ret < 0)
    {
        perror("recvfrom error");
        return -1;
    }
    char *peerip = inet_ntoa(peer.sin_addr);//将网络字节序地址转换为字符串
    uint16_t port = ntohs(peer.sin_port);//将网络字节序端口,转换为主机字节序端口
    printf("client[%s:%d] say:%s\n", peerip, port, buf);

//4,发送数据
    char data[1024]= 0;
    printf("server say:");
    fflush(stdout);
    scanf("%s", data);
    ret = sendto(sockfa, data, strlen(data), 0, (struct sockaddr*)&peer, len);
    if(ret < 0)
    {
        perror("sendto error");
        return -1;
    }

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

4.实现一个UDP通信客户端

封装一个UdpSocket类,简化用户对socket的操作

代码在xshell ,UDP文件夹中

猜你喜欢

转载自blog.csdn.net/weixin_59215611/article/details/130698610
今日推荐