当前位置: 首页 > article >正文

使用udp进行通信

UDP chat

头文件

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

服务端server

typedef struct sockaddr *(SA);
int main(int argc,char *argv[])
{
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        return 1;
    }

    struct sockaddr_in server,client;
    bzero(&server,sizeof(server));
    bzero(&client,sizeof(client));
    server.sin_family = AF_INET;
    server.sin_port = htons(50000);
    server.sin_addr.s_addr = 0;
    int ret = bind(sockfd,(SA)&server,sizeof(server));
    if(-1 == ret)
    {
        perror("bind");
        exit(1);
    }
    char buf[512] = {0};
    socklen_t len = sizeof(client);
    recvfrom(sockfd,buf,sizeof(buf),0,(SA)&client,&len);
    printf("cli addr:%s port:%s\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
    pid_t pid = fork();
    if(pid>0)
    {
        while(1)
        {
            bzero(buf,sizeof(buf));
            recvfrom(sockfd,buf,sizeof(buf),0,(SA)&client,&len);
            if(0==strcmp(buf,"#quit\n"))
            {
                kill(pid,2);
                exit(1);
            }    
            printf("from cli:%s\n",buf);
            fflush(stdout);
        }
    }
    else if(0 == pid)
    {
        while(1)
        {
            bzero(buf,sizeof(buf));
            printf("to cli:");
            fgets(buf,sizeof(buf),stdin);
            sendto(sockfd,buf,strlen(buf),0,(SA)&client,sizeof(client));
            if(0 == strcmp(buf,"#quit\n"))
            {
                kill(getppid(),2);
                exit(1);
            }
        }
    }
    else
    {
        perror("fork");
        exit(1);
    }
    return 0;
        
}

客户端client

typedef struct sockaddr * (SA);
    struct sockaddr_in server;
void* th1(void* arg)
{
    int sockfd  = *(int*)arg;
    while(1)
    {
        char buf[512]={0};
        recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL);
        if(0 == strcmp(buf,"#quit\n"))
        {
            exit(0);
        }
        printf("from ser:%s\n",buf);
    }
    return NULL;
}
void* th2(void* arg)
{
    int sockfd  = *(int*)arg;
    while(1)
    {
        char buf[512]={0};
        printf("to ser:");
        fgets(buf,sizeof(buf),stdin);
        sendto(sockfd,buf,strlen(buf),0,(SA)&server,sizeof(server));
        if(0 == strcmp("#quit\n",buf))
        {
            exit(0);
        }
    }
    return NULL;
}

int main(int argc, char *argv[])
{
    int sockfd  =socket(AF_INET,SOCK_DGRAM ,0);
    if(-1 == sockfd)
    {
        perror("socket");
        return 1;

    }
    //set ip port  man 7 ip 
    bzero(&server,sizeof(server));
    server.sin_family  = AF_INET;
    server.sin_port  = htons(50000);// >50000 host to net short 
    server.sin_addr.s_addr =0;
   
    char buf[512]="@_@";
    sendto(sockfd,buf,strlen(buf),0,(SA)&server,sizeof(server));
    pthread_t tid1,tid2;
    pthread_create(&tid1,NULL,th1,&sockfd);
    pthread_create(&tid2,NULL,th2,&sockfd);
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    return 0;
}

函数

socket

int socket(int domain, int type, int protocol);
  • domain: 指定通信协议族,这里使用的是AF_INET,表示使用IPv4协议。
  • type: 指定套接字类型,SOCK_DGRAM表示使用数据报套接字,也就是UDP协议。
  • protocol: 通常为0,表示选择默认协议,对于SOCK_DGRAM来说,默认的协议就是UDP。

创建udp套接字  int sockfd = socket(AF_INET, SOCK_DGRAM, 0)

sockfd = socket(int socket_family, int socket_type, int protocol);

bzero

bzero 是一个用于将指定内存区域清零的函数,通常用于初始化数据结构,以确保它们不包含任何未初始化的数据。

void bzero(void *s, size_t n);
  • s: 指向需要清零的内存区域的指针。
  • n: 要清零的字节数。

bzero 将从指针 s 所指向的内存区域开始的 n 个字节全部设置为零。

struct sockaddr_in server;
bzero(&server, sizeof(server));

bzero 在网络编程中初始化 sockaddr_in 结构体:

bzeroserver 结构体的所有字节都设置为零,确保其中的每个字段都被正确初始化。使用 bzero 比逐个字段手动初始化要简单得多。

sendto

sendto 是一个用于发送数据到指定目标地址的函数,常用于UDP(数据报套接字)的网络编程。与TCP不同,UDP是无连接的协议,使用sendto函数可以在不建立连接的情况下发送数据。

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,除非需要设置特殊的发送选项。
  • dest_addr: 指向目的地址的指针,即目标主机的地址和端口信息。这个地址通常使用 sockaddr_in 结构体表示。
  • addrlen: dest_addr 结构体的大小,通常使用 sizeof(struct sockaddr_in)

recvfrom

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);
  • sockfd: 套接字文件描述符,指定从哪个套接字接收数据。
  • buf: 指向接收数据的缓冲区指针。
  • len: 缓冲区的大小(字节数),即可以接收的最大数据量。
  • flags: 通常设置为 0,除非需要特殊的接收行为(如非阻塞模式)。
  • src_addr: 用于存储发送方的地址信息的结构体指针(通常是 sockaddr_in 类型)。如果不关心发送方地址,可以设置为 NULL
  • addrlen: 一个指向 socklen_t 类型变量的指针,用于存储发送方地址的长度。如果 src_addrNULL,这个参数可以忽略。

bind

bind 函数在网络编程中用于将一个套接字(socket)绑定到一个特定的IP地址和端口号上。通常在服务器端程序中使用,以指定该服务器在某个IP地址和端口上监听客户端的连接或数据。

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd: 套接字文件描述符,指示要绑定的套接字。
  • addr: 指向包含IP地址和端口信息的 sockaddr 结构体的指针。对于IPv4,通常使用 sockaddr_in 结构体来表示。
  • addrlen: addr 结构体的大小,通常使用 sizeof(struct sockaddr_in)
  • 服务器端bind 是服务器端程序中必须的步骤之一,它将服务器的套接字绑定到一个特定的IP地址和端口上,以便客户端能够通过这个地址和端口与服务器通信。
  • 客户端:对于客户端程序,通常不需要手动调用 bind,因为系统会自动为客户端分配一个临时端口。然而,如果客户端希望指定特定的源IP地址或端口,也可以使用 bind

http://www.kler.cn/news/290153.html

相关文章:

  • 视频结构化从入门到精通——行为分析类应用
  • IEEE PDF eXpress 报错解决 Error in converting file + font not embedded
  • 海康二次开发学习笔记9-通讯触发及模块列表获取
  • LLM手撕
  • JS笔记
  • js逆向——RSA实战案例讲解
  • UART串口通信——FPGA学习笔记9
  • tekton什么情况下在Dockerfile中需要用copy
  • anaconda创建虚拟环境
  • 机器学习数学公式推导之高斯分布
  • 雨情教务排课系统
  • 数字化转型升级探索(二)
  • Java | Leetcode Java题解之第387题字符串中的第一个唯一字符
  • 计算机网络 数据链路层2
  • 网络编程学习:TCP/IP协议
  • 【安全科普】学完网络安全出去能做什么工作?
  • 【ES实战】Elasticsearch中Task的简单管理说明
  • css加载一张图片 设置整个页面背景
  • 淘宝扭蛋机小程序开发,吸引更多的消费者
  • 【嵌入式学习笔记】---- STM32里的DMA
  • 小皮面板webman ai项目本地启动教程
  • 阿里云技术深度解析与实战应用:构建高效短信验证系统
  • 9/3 链表-力扣160 、203、206
  • Redis进阶(二)--Redis高级特性和应用
  • 总线操作与定时
  • 当采用 JSON 格式的数据进行响应时,对象是否需要序列化取决于什么?
  • 9/4 链表-力扣 234、19
  • MySQL Email验证流程详解:从注册到激活!
  • Proxyless的多活流量和微服务治理
  • 重生之我们在ES顶端相遇第10 章- 分分分词器的基本使用