Linux下网络编程-UDP协议探测在线好友

简介: 这篇文章介绍Linux下UDP协议的基本使用,完成数据发送,接收。

1. UDP协议介绍

UDP协议 相对TCP协议来讲属于不可靠协议,UDP协议是广播方式发送数据,没有服务器和客户端的概念。

在Linux下使用socket创建UDP的套接字时,属性要选择数据报类型SOCK_DGRAM

 sockfd=socket(AF_INET,SOCK_DGRAM,0);

2. UDP协议发送和接收数据的函数

2.1 recvfrom函数

UDP使用recvfrom()函数接收数据,他类似于标准的read(),但是在recvfrom()函数中要指明数据的目的地址。

#include <sys/types.h>  
#include <sys/socket.h>  
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr * from, size_t *addrlen);

返回值

成功返回接收到数据的长度,负数失败 

前三个参数等同于函数read()的前三个参数,flags参数是传输控制标志。最后两个参数类似于accept的最后两个参数(接收客户端的IP地址)。

2.2 sendto函数

UDP使用sendto()函数发送数据,他类似于标准的write(),但是在sendto()函数中要指明目的地址。

#include <sys/types.h>  
#include <sys/socket.h>  
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr * to, int addrlen);

返回值

成功返回发送数据的长度,失败返回-1

前三个参数等同于函数read()的前三个参数,flags参数是传输控制标志。

参数to指明数据将发往的协议地址,他的大小由addrlen参数来指定。

2.3 设置套接字属性

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

setsockopt()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。选项影响套接口的操作,诸如加急数据是否在普通数据流中接收,广播数据是否可以从套接口发送等等。

参数

sockfd:标识一个套接口的描述字。

level:选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。

optname:需设置的选项。

optval:指针,指向存放选项值的缓冲区。

optlen:optval缓冲区的长度。

UDP协议发送数据时,设置具有广播特性: 默认情况下socket不支持广播特性

char bBroadcast=1;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(char));

3. 案例: UDP协议数据收发

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/epoll.h>
#include <poll.h>


#define SEND_MSG "1314520"   //发送的数据包
#define PORT 8888           //固定的端口号

int sockfd;
int main(int argc,char **argv)
{   
    if(argc!=2)
    {
        printf("./app <广播地址>  当前程序固定的端口号是8888\n");
        return 0;
    }

    /*1. 创建socket套接字*/
    sockfd=socket(AF_INET,SOCK_DGRAM,0);

    //设置端口号的复用功能
    int on = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

    /*2. 绑定端口号与IP地址*/
    struct sockaddr_in addr;
    addr.sin_family=AF_INET;
    addr.sin_port=htons(PORT); // 端口号0~65535
    addr.sin_addr.s_addr=INADDR_ANY;    //inet_addr("0.0.0.0"); //IP地址
    if(bind(sockfd,(const struct sockaddr *)&addr,sizeof(struct sockaddr))!=0)
    {
        printf("UDP服务器:端口号绑定失败.\n");
        return 0;
    }

    /*3. 接收数据*/
    unsigned char buff[1024+1];
    int cnt;
    struct sockaddr_in client_addr;
    socklen_t addrlen=sizeof(struct sockaddr_in);

    struct pollfd fds;
    fds.fd=sockfd;
    fds.events=POLLIN;
    while(1)
    {
        cnt=poll(&fds,1,1000);
        if(cnt>0)
        {
            cnt=recvfrom(sockfd,buff,1024,0,(struct sockaddr *)&client_addr,&addrlen);
            buff[cnt]='\0';
            
            //判断是不是探测包数据
            if(strcmp(buff,SEND_MSG)==0)
            {
                printf("在线好友:%s,%d-->%s:%d\n",buff,cnt,inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
                cnt=sendto(sockfd,SEND_MSG,strlen(SEND_MSG),0,(const struct sockaddr *)&client_addr,sizeof(struct sockaddr));
                printf("回应探测包:%d字节.\n",cnt);

                //这里可以继续写代码,将存在的好友保存在链表,并记录在线好友数量
            }
        }
        else
        {
            ssize_t cnt;
            struct sockaddr_in addr;
            addr.sin_family=AF_INET;
            addr.sin_port=htons(PORT); // 端口号0~65535
            addr.sin_addr.s_addr=inet_addr(argv[1]); //IP地址

            cnt=sendto(sockfd,SEND_MSG,strlen(SEND_MSG),0,(const struct sockaddr *)&addr,sizeof(struct sockaddr));
            printf("探测包发送:%d字节.\n",cnt);
        }
    }
    return 0;
}

4. 案例: 使用UDP协议探测在线好友

前面几篇文章介绍了Linux下TCP协议设计的群聊天室的一个程序,如果想要知道同一个网络下有多少好友在线,就可以使用UDP协议进行广播探测。 大家的端口号是固定的,也就是只要在这个网络范围内,大家都跑这个同一个聊天室程序,就可以互相探测,得到对方IP地址之后,再完成TCP协议建立,完成点对点聊天通信。

#include <stdio.h>    
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <libgen.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥锁
#define CLIENT_COUNT 100 //服务器可容纳客户端数量
#define SERVER_PORT 8080 //服务器端口号

/*----------------------------链表相关函数----------------------------*/
/*---------------------存储客户端信息和线程ID结构体-------------------*/
//存储客户端信息和线程ID结构体
typedef struct node
{
    int nfds;            //客户端套接字
    pthread_t phid;        //线程ID
    char name[50];    //用户名
    struct node *next;
}node, *ptr_node;

//链队列
typedef struct
{
    ptr_node head, tail;
}qlink;

/**********************
    链表初始化
**********************/
void qlink_Init(qlink *s)
{
    s->head = s->tail = (ptr_node)malloc(sizeof(node));
    if(s->tail == NULL)
    {
        printf("创建节点失败!\n");
        exit(0);
    }
    s->head->next = NULL;
}
/****************************************
 添加节点
 参数:
        s --- 链表
        c --- 客户端套接字
      phid --- 线程ID
*****************************************/
void qlink_Add(qlink *s, int c, pthread_t phid)
{
    pthread_mutex_lock(&mutex);  //互斥锁上锁(带阻塞)
    ptr_node p;
    p = (ptr_node)malloc(sizeof(node));
    if (p == NULL)
    {
        printf("创建节点失败[2]!\n");
        exit(0);
    }
    p->nfds = c;
    p->phid = phid;
    p->next = s->head->next;
    s->head->next = p;
    pthread_mutex_unlock(&mutex);//互斥锁解锁
}
/*--------------------------------END---------------------------------*/
/****************************全局变量定义******************************/
qlink s;            //链表
pthread_t phid;    //线程ID
int sockfd_UDP;            //UDP套接字
int Find_user = 0;        //找到用户标志位
int f_dp;        //TCP客户端套接字
int server_flag = 0;        //当成服务器
int client_flag = 0;        //当成客户端
/*---------------------------发送数据结构体---------------------------*/
typedef struct UDP_Test
{
    char name[50];//用户名
    char buff[100];//发送数据,探测数据:UDP_TEST
    int flag;//1表示探测好友,2好友回复,3正常数据
}UDP_Test;
struct UDP_Test recv_msg;            //接收信息结构体
struct UDP_Test send_msg;            //发送信息结构体
/*--------------------------------END---------------------------------*/
/**********************************************************************/


/**********************************************************************/


/*****************************
    信号捕获函数 
*****************************/
void signal_capture(int sig)
{
    if(sig==SIGSEGV)//段错误
    {
        time_t sec=time(NULL); //获取系统秒单位时间    
        char buff[50];
        struct tm *time;
        time=localtime(&sec); //秒单位时间转换时间结构体
        strftime(buff,sizeof(buff),"%Y/%m/%d %k:%M:%S\n",time);
        printf("段错误时间:%s\n",buff);
    }
    else
    {
        #if 0
        ptr_node p = s.head->next;
        while(p != NULL)
        {
            printf("已清理资源!p->nfds = %d\n", p->nfds);
            close(p->nfds);
            pthread_cancel(p->phid);//杀死线程
            p = p->next;
        }
        free(s.head);
        #endif
    }
    printf("服务器资源清理完成\n");
    exit(0);
}
/*--------------------------------END---------------------------------*/
/****************************
    线程工作函数 
****************************/
void *start_routine(void *arg)
{
    #if 0
    int f_dp = *(int *)arg;
    memset(&send_msg, 0, sizeof(send_msg));
    char buff[100];
    while (1)
    {
        scanf("%s", buff);    
        strncpy(send_msg.name, "777" ,sizeof(send_msg.name));//用户名 
        strncpy(send_msg.buff, buff, sizeof(buff));//探测消息内容
        
        printf("send_msg.buff = %s\n", send_msg.buff);
        write(f_dp, &send_msg, sizeof(send_msg));
        usleep(100);
    }
    #endif
    char buff[50];
    int cho = *(int *)arg;
    if(cho == 1)            //写数据线程
    {
        memset(&send_msg, 0, sizeof(send_msg));
        while (1)
        {
            scanf("%s", buff);    
            //strncpy(send_msg.name, buff ,sizeof(send_msg.name));//用户名
            strncpy(send_msg.buff, buff, sizeof(buff));//探测消息内容
            
            printf("send_msg.buff = %s\n", send_msg.buff);
            write(f_dp, &send_msg, sizeof(send_msg));
            usleep(100);
        }
        pthread_exit(NULL);
    }
    else                    //读数据线程
    {
        int res, cnt;
        fd_set readfds;//读事件
        struct timeval timeout;
        struct UDP_Test read_msg;
        while (2)
        {
            FD_ZERO(&readfds);
            FD_SET(f_dp, &readfds);
            timeout.tv_sec = 0;
            timeout.tv_usec = 0;
            res = select(f_dp + 1, &readfds, NULL, NULL, &timeout);
            if(res > 0)
            {
                cnt = read(f_dp, &read_msg, sizeof(read_msg));
                if(cnt > 0)
                {
                    printf("接收到数据: name:%s \t data:%s\n", read_msg.name, read_msg.buff);            //接收到了对方的用户名
                    //break;
                }
                else
                {
                    printf("好友下线!\n");
                    break;
                }
            }
            else if(res < 0)
            {
                printf("错误!\n");
            }
            usleep(100);
        }
        pthread_exit(NULL);
    }
    
}
/*--------------------------------END---------------------------------*/
/***********************
 用于接收探测返回信息
***********************/
void *Receive_probe_retur(void *arg)
{
    memset(&recv_msg, 0, sizeof(recv_msg));
    fd_set readfds;//读事件
    struct timeval timeout;
    int res, cnt;
    struct sockaddr_in src_addr;            //保存其它用户的ip地址和端口号
    socklen_t addrlen = sizeof(struct sockaddr_in);
    while(1)    //等待接收消息
    {
        FD_ZERO(&readfds);
        timeout.tv_sec=0;
        timeout.tv_usec=0;
        FD_SET(sockfd_UDP,&readfds);
        res = select(sockfd_UDP+1, &readfds, NULL, NULL, &timeout);
        if(res > 0)
        {
            cnt = recvfrom(sockfd_UDP, &recv_msg, sizeof(struct UDP_Test), 0, (struct sockaddr*)&src_addr, &addrlen);
            if(cnt > 0)
            {
                if(recv_msg.flag == 2)        //接收到返回信息
                {
                    printf("接收到%s用户的确认信息\n", recv_msg.name);
                    client_flag = 3;        //该用户当作客户端
                    Find_user = 1;            //标志搜索到用户,主线程不用再发探测信息了
                    usleep(200);
                    break;
                }            
            }
        }
        else if(res < 0)
        {
            printf("错误!\n");
        }
    }
    pthread_exit(NULL);        //杀死线程
}

int main(int argc,char *argv[])
{
    
    if(argc!=2)
    {
        printf("./a.out <用户名>\n");
        return 0;
    }
    
    signal(SIGPIPE,SIG_IGN);//忽略SIGPIPE信号
    signal(SIGINT, signal_capture);            //捕获CTRL+c
    signal(SIGSEGV, signal_capture);            //捕获段错误

    /* 初始化链表 */
    qlink_Init(&s);
    
    /*--------------------------通过UDP获取在线用户信息--------------------------*/
    /*1.创建套接字*/
    sockfd_UDP = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd_UDP == -1)
    {
        printf("创建套接字失败\n");
        return 0;
    }
    /*绑定端口号*/
    struct sockaddr_in addr;
    addr.sin_family=AF_INET;//IPV4
    addr.sin_port=htons(SERVER_PORT);//端口号
    addr.sin_addr.s_addr=INADDR_ANY;//本地所有IP(0.0.0.0)
    if(bind(sockfd_UDP,(struct sockaddr*)&addr,sizeof(struct sockaddr_in)))
    {
        printf("绑定端口号失败\n");
        close(sockfd_UDP);
        return 0;
    }
    ssize_t cnt;
    /*获取广播地址*/
    //ifconfig -a |grep broadcast|awk '{print $6}'|tr -d broadcast: -- ubuntu下获取本地广播地址
    //ifconfig -a |grep Bcast|awk '{print $3}'|tr -d Bcast:  --red hat下获取本地广播地址
    FILE *fp = popen("ifconfig -a |grep broadcast|awk '{print $6}'|tr -d broadcast:", "r");
    char ip_addr[20];
    cnt = fread(ip_addr, 1, sizeof(ip_addr) - 1, fp);
    ip_addr[cnt]='\0';
    printf("广播地址:%s\n",ip_addr);
    pclose(fp);
    addr.sin_addr.s_addr=inet_addr(ip_addr);//广播IP地址
    //设置该套接字为广播类型
    const int opt = 1;
    int nb = 0;
    nb = setsockopt(sockfd_UDP, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt));
    if(nb == -1)
    {
        printf("设置广播类型错误.\n");
        close(sockfd_UDP);
        return 0;
    }    

    /*-----------------------------接收探测信息-----------------------------*/
    fd_set readfds;//读事件
    struct timeval timeout;
    int res;
    struct sockaddr_in src_addr;            //保存其它用户的ip地址和端口号
    socklen_t addrlen = sizeof(struct sockaddr_in);
    
    int count = 0;
    memset(&recv_msg, 0, sizeof(recv_msg));
    memset(&send_msg, 0, sizeof(send_msg));
    /* 循环等待 5秒 探测信息 */
    while(1)
    {
        FD_ZERO(&readfds);
        timeout.tv_sec=0;
        timeout.tv_usec=0;
        FD_SET(sockfd_UDP,&readfds);
        res = select(sockfd_UDP+1, &readfds, NULL, NULL, &timeout);
        if(res>0)
        {
            cnt = recvfrom(sockfd_UDP, &recv_msg, sizeof(struct UDP_Test), 0, (struct sockaddr*)&src_addr, &addrlen);
            if(cnt > 0)
            {
                if(recv_msg.flag == 1)        //接收到其它用户发出的探测信息,得到对方的IP地址
                {
                    printf("user addr:%s \t user port:%d\n", inet_ntoa(src_addr.sin_addr), ntohs(src_addr.sin_port));
                    printf("接收到数据: name:%s \t data:%s\n", recv_msg.name, recv_msg.buff);            //接收到了对方的用户名
                    
                    /* 当接收到探测信息后,返回确认收到信息给该用户 */
                    strncpy(send_msg.name, argv[1], sizeof(send_msg.name));//用户名
                    send_msg.flag = 2;//确认收到探测信息标志
                    cnt = sendto(sockfd_UDP, &send_msg, sizeof(struct UDP_Test), 0, (const struct sockaddr *)&addr, sizeof(struct sockaddr_in));
                    printf("确认消息发送成功\n");
                    /*--------------------------------------------------------------*/
                    
                    printf("搜索到在线用户 %s\n", recv_msg.name);
                    client_flag = 3;        //接收到探测信息,该用户当作客户端
                    //qlink_Add(&s, , pthread_t phid);
                    close(sockfd_UDP);
                    break;
                }            
            }
        }
        else if(res < 0)
        {
            printf("错误!\n");
        }
        usleep(100);
        count++;
        if(count >= 50000)        //若是5秒后还没有接收到探测信息,则跳出循环
        {
            count = 0;
            server_flag = 3;    //设置成服务器
            break;
        }
    }
    /*----------------------------------END--------------------------------*/
/****************************************************客户端***********************************************************/    
    if(client_flag == 3)        //标志在此次是客户端
    {
        /*1.创建套接字*/
        int sockfd_c = socket(AF_INET, SOCK_STREAM, 0);
        if(sockfd_c == -1)
        {
            printf("创建网络套接字失败\n");
            return 0;
        }
        /*2.连接服务器*/
        struct sockaddr_in t_addr;
        char buff[20];
        strcpy(buff, inet_ntoa(src_addr.sin_addr));
        int n = strlen(buff);
        buff[n] = '\0';
        printf("buff:%s\n", buff);
        t_addr.sin_family = AF_INET;//IPV4
        t_addr.sin_port = htons(8089);//端口号
        t_addr.sin_addr.s_addr = inet_addr(buff);//服务器IP
    
        while(1)
        {
            printf("准备连接服务器:connect addr:%s \t user port:%d\n", inet_ntoa(t_addr.sin_addr), ntohs(t_addr.sin_port));
            
            printf("sockfd_c:%d\n",sockfd_c);
            if(connect(sockfd_c, (const struct sockaddr *)&t_addr, sizeof(struct sockaddr_in)))
            {
                printf("连接失败:%s,%d\n",strerror(errno),errno);
                sleep(2);
            }
            else
            {
                printf("服务器连接成功\n");
                break;
            }
        }
        
        
        /*-----------------------将自己的用户信息发送过去----------------------*/
        memset(&send_msg, 0, sizeof(send_msg));
        strncpy(send_msg.name,argv[1],sizeof(send_msg.name));//用户名
        write(sockfd_c, &send_msg, sizeof(send_msg));        //将用户信息发送过去
        /*----------------------------------END--------------------------------*/
        while(1);
        
    }
/****************************************************服务器***********************************************************/
    else if(server_flag = 3)        //标志在此次是服务器
    {
        memset(&send_msg, 0, sizeof(send_msg));
        pthread_t phid_1;
        pthread_create(&phid_1, NULL, Receive_probe_retur, NULL);        //创建线程 用于接收探测返回信息
        /************************************主线程循环发送探测消息******************************************/
        while(1)
        {
            strncpy(send_msg.name, argv[1], sizeof(send_msg.name));//用户名
            //strncpy(send_msg.buff, "UDP_TEST", sizeof(send_msg.buff));//探测消息内容
            send_msg.flag = 1;//探测消息标志
            cnt = sendto(sockfd_UDP, &send_msg, sizeof(struct UDP_Test), 0, (const struct sockaddr *)&addr, sizeof(struct sockaddr_in));
            printf("探测消息发送成功\n");
            if(Find_user == 1)        //标志在子线程内找到了在线用户
            {
                break;
            }
            sleep(1);
        }
        /*****************************开始创建TCP服务器********************************/
        /* 创建套接字 */
        int sockfd_TCP = socket(AF_INET, SOCK_STREAM, 0);
        if(sockfd_TCP == -1)
        {
            printf("网络套接字创建失败\n");
            return 0;
        }
        /*允许绑定已使用的端口号*/
        int on = 1;/*  */
        setsockopt(sockfd_TCP, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
        
        /* 绑定端口号 */
        struct sockaddr_in s_addr;
        s_addr.sin_family = AF_INET;        //设置为IPV4
        s_addr.sin_port = htons(8089);//端口号
        s_addr.sin_addr.s_addr = INADDR_ANY;     //IP地址,该参数是让系统随机分配
        if(bind(sockfd_TCP, (const struct sockaddr *)&s_addr, sizeof(s_addr)))
        {
            printf("绑定端口号失败!\n");
            return 0;
        }
        //设置监听数量
        listen(sockfd_TCP, 100);
        /* 等待客户端连接 */
        int i;
        pthread_t phid[2];
        int *p;
        printf("已跳出循环\n");
        while(1)
        {
            struct sockaddr_in c_addr;    //客户端属性信息
            socklen_t c_addr_len = sizeof(struct sockaddr_in);
            f_dp = accept(sockfd_TCP, (struct sockaddr *)&c_addr, &c_addr_len);
            printf("%d客户端连接成功,ip=%s:%d\n",f_dp,inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port));
            read(f_dp, &recv_msg, sizeof(recv_msg));        //第一次读取用户信息
            printf("user name = %s\n", recv_msg.name);
            for (i = 1; i <= 2; i++)
            {
                p = malloc(sizeof(int));
                *p = i;
                pthread_create(&phid[i - 1], NULL, start_routine, p);            //创建线程    -- i == 1是读, i ==2写
                pthread_detach(phid[i - 1]);//设置为分离属性
            }        
        } 
    }
    /*----------------------------------END--------------------------------*/
    #if 0
    pthread_t phid;
    int *p = malloc(sizeof(int));
    *p = sockfd_c;
    pthread_create(&phid, NULL, start_routine, p);        //创建线程
    pthread_detach(phid);                    //设置分离属性
    /*-------------------------------主线程读------------------------------*/
    struct UDP_Test re_msg;    //存储读到的数据
    fd_set readfds_2;//读事件
    while(1)
    {
        FD_ZERO(&readfds_2);//初始化读事件
        FD_SET(sockfd_c,&readfds_2);//添加要监测的描述符到读事件集合中
        timeout.tv_sec=0;
        timeout.tv_usec=0;
        //printf("用户 \n");
        res = select(sockfd_c + 1, &readfds_2, NULL, NULL, &timeout);
        if(res > 0)    //当有数据的时候进行上锁
        {
            memset(&re_msg, 0, sizeof(re_msg));
            pthread_mutex_lock(&mutex);  //互斥锁上锁(带阻塞)
            int n = read(sockfd_c, &re_msg, sizeof(re_msg));        //读取数据
            if(n <= 0)
            {
                printf("好友下线!\n");
                break;
            }
            else
            {
                printf("用户 %s\t 消息 %s\n", re_msg.name, re_msg.buff);
            }
            pthread_mutex_unlock(&mutex);//互斥锁解锁
        }
        else if(res < 0)
        {
            printf("select函数出错!\n");
            break;
        }
        usleep(100);
    }
    #endif
    /*----------------------------------END--------------------------------*/
    return 0;
}

image-20211202143124060

目录
相关文章
|
2天前
|
网络协议
Qt中的网络编程(Tcp和Udp)运用详解以及简单示范案例
Tcp和Udp是我们学习网络编程中经常接触到的两个通讯协议,在Qt也被Qt封装成了自己的库供我们调用,对于需要进行网络交互的项目中无疑是很重要的,希望这篇文章可以帮助到大家。 是关于Qt中TCP和UDP的基本使用和特点:
|
2天前
|
存储 网络协议 Ubuntu
【Linux开发实战指南】基于UDP协议的即时聊天室:快速构建登陆、聊天与退出功能
UDP 是一种无连接的、不可靠的传输层协议,位于IP协议之上。它提供了最基本的数据传输服务,不保证数据包的顺序、可靠到达或无重复。与TCP(传输控制协议)相比,UDP具有较低的传输延迟,因为省去了建立连接和确认接收等过程,适用于对实时性要求较高、但能容忍一定数据丢失的场景,如在线视频、语音通话、DNS查询等。 链表 链表是一种动态数据结构,用于存储一系列元素(节点),每个节点包含数据字段和指向下一个节点的引用(指针)。链表分为单向链表、双向链表和循环链表等类型。与数组相比,链表在插入和删除操作上更为高效,因为它不需要移动元素,只需修改节点间的指针即可。但访问链表中的元素不如数组直接,通常需要从
|
2天前
|
网络协议 网络架构
【网络编程入门】TCP与UDP通信实战:从零构建服务器与客户端对话(附简易源码,新手友好!)
在了解他们之前我们首先要知道网络模型,它分为两种,一种是OSI,一种是TCP/IP,当然他们的模型图是不同的,如下
|
2天前
|
网络协议 安全 Ubuntu
7 个有用的免费 Linux 网络隧道
【7月更文挑战第4天】
12 0
7 个有用的免费 Linux 网络隧道
|
2天前
|
网络协议 Linux 开发工具
配置Linux固定IP地址,为什么要固定IP,因为他是通DHCP服务获取的,DHCP服务每次重启都会重新获取一次ip,VMware编辑中有一个虚拟网络编辑器
配置Linux固定IP地址,为什么要固定IP,因为他是通DHCP服务获取的,DHCP服务每次重启都会重新获取一次ip,VMware编辑中有一个虚拟网络编辑器
|
2天前
|
传感器 算法
基于LEACH路由协议的网络性能matlab仿真,包括数据量,能耗,存活节点
- **LEACH协议**在WSN中通过分簇减少能耗,普通节点向最近簇头发送数据,簇头融合后发送给基站。本项目研究LEACH在不同初始能量、数据包及控制包长度条件下的网络性能,如剩余节点、能量、接收数据量和累计接收量。
|
4天前
|
人工智能 缓存 网络协议
网络层之三层交换、icmp协议、arp协议
网络层之三层交换、icmp协议、arp协议
|
4天前
|
缓存 网络协议 网络性能优化
计算机网络—传输层-tcp、udp协议详解
计算机网络—传输层-tcp、udp协议详解
|
4天前
|
域名解析 网络协议 Linux
linux网络-- 手动配置ip地址
linux网络-- 手动配置ip地址
|
4天前
|
网络协议 Linux 分布式数据库
【Linux】DNS系统,ICMP协议,NAPT技术详解
NAPT(Network Address Port Translation),也被称为端口地址转换,是一种NAT(网络地址转换)的形式。NAPT允许多个设备在内部网络上使用私有IP地址,并通过单个公共IP地址与外部网络进行通信。NAPT通过改变传输层的端口号来实现这一点,从而允许多个内部设备共享同一个公共IP地址。
10 0