Linux下基于UDP的简易多人聊天室创建——群聊、私聊、上线通知(Socket编程)

Linux下基于UDP的简易多人聊天室创建(Socket编程)

  • OSI和TCP/IP:
  • 关于TCP/IP协议
  • 关于UDP协议
    • UDP编程的一般步骤[^2]
  • Socket套接字网络编程
  • UDP网络聊天室实现
    • 功能概述
      • 服务器编程
      • 客户端编程
      • 运行结果
  • 总结
    • 遇到的问题
      • 服务器编程
      • 客户端编程

本文采用的是 多线程的方式实现信息的接收和广播以及输入的等待,之前采用的 多进程方案后来由于 僵尸进程过多会导致系统的处理压力越来越大。我没有想到对于多进程下更好的解决方案,所以使用多线程来解决这个问题,这样一来很好的避免了僵尸进程的问题,如果大家有更好的多进程处理方法也欢迎和我交流!

OSI和TCP/IP:

OSI 模型本身不是网络体系结构的全部内容,它并未确切地描述用于各层的协议和服务,仅提出每一层应该做什么。不过OSI 已经为各层制定了标准,但并不是参考模型的一部分,而作为单独的国际标准公布的。
TCP/IP 是一组用于实现网络互连的通信协议。Internet 网络体系结构以TCP/IP 为核心。基于TCP/IP 的参考模型将协议分成四个层次,它们分别是:网络访问层、网际互联层、传输层(主机到主机)、和应用层。
OSI模型和TCP/IP模型的对应关系

关于TCP/IP协议

TCP/IP是一个网络通信模型,以及一整个网络传输协议家族,是网际网络的基础通信架构。因为该协议家族的两个核心协议:TCP(传输控制协议)和IP(网际协议),为该家族中最早通过的标准。故此它常被通称为TCP/IP协议族(TCP/IP Protocol Suite),简称TCP/IP。

. TCP/IP模型 :TCP/IP 是一组用于实现网络互连的通信协议。Internet 网络体系结构以 TCP/IP 为核心。基于TCP/IP 的参考模型将协议分成四个层次,它们分别是:网络访问层、网际互联层、传输层(主机到主机)、和应用层。

  1. 应用层
    应用层对应于 OSI 参考模型的高层,为用户提供所需要的各种服务,例如:FTP、Telnet、DNS、SMTP 等。
  2. 传输层
    传输层对应于 OSI 参考模型的传输层,为应用层实体提供端到端的通信功能,保证了数据包的顺序传送及数据的完整性。该层定义了两个主要的协议:传输控制协议(TCP)和用户数据协议(UDP)。TCP 协议提供的是一种可靠的、通过“三次握手”来连接的数据传输服务;而 UDP 协议提供的则是不保证可靠的(并不是不可靠)、无连接的数据传输服务.
  3. 网际互联层网际互联层对应于 OSI 参考模型的网络层,主要解决主机到主机的通信问题。它所包含的协议设计数据包在整个网络上的逻辑传输。注重重新赋予主机一个 IP 地址来完成对主机的寻址,它还负责数据包在多种网络中的路由。该层有三个主要协议:网际协议(IP)、互联网组管理协议(IGMP)和互联网控制报文协议(ICMP)。IP 协议是网际互联层最重要的协议,它提供的是一个可靠、无连接的数据报传递服务。
  4. 网络接口层(即主机-网络层)
    网络接入层与 OSI 参考模型中的物理层和数据链路层相对应。它负责监视数据在主机和网络之间的交换。事实上,TCP/IP 本身并未定义该层的协议,而由参与互连的各网络使用自己的物理层和数据链路层协议,然后与 TCP/IP 的网络接入层进行连接。地址解析协议(ARP)工作在此层,即 OSI 参考模型的数据链路层;

. IP协议 :IP(Internet Protocol)协议是 TCP/IP 的核心协议。IP 协议(Internet Protocol)又称互联网协议,是支持网间互连的数据报协议。它提供网间连接的完善功能, 包括 IP 数据报规定互连网络范围内的 IP 地址格式。
目前的 IP 地址(IPv4:IP 第 4 版本)由 32 个二进制位表示,每 8 位二进制数为一个整数,中间由小数点间隔,如 159.226.41.98,整个 IP 地址空间有 4 组 8 位二进制数,由表示主机所在的网络的地址以及主机在该网络中的标识共同组成,它通常被分为A,B,C,D,E五类,其中商业应用只用到A,B,C三类1
在这里插入图片描述

关于UDP协议

UDP 协议(用户数据报协议)是建立在 IP 协议基础之上的,用在传输层的协议。UDP 提供了无连接的数据报服务。UDP 和 IP 协议一样,是不可靠的数据报服务。

  1. UDP 提供无连接服务
  2. UDP 缺乏可靠性支持,应用程序必须实现:确认、超时、重传、流控等
  3. UDP 面向记录服务

UDP编程的一般步骤2

  1. UDP编程的服务器端一般步骤是:
      1、创建一个socket,用函数socket();
      2、设置socket属性,用函数setsockopt();* 可选
      3、绑定IP地址、端口等信息到socket上,用函数bind();
      4、循环接收数据,用函数recvfrom();
      5、关闭网络连接;

  2. UDP编程的客户端一般步骤是:
      1、创建一个socket,用函数socket();
      2、设置socket属性,用函数setsockopt();* 可选
      3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
      4、设置对方的IP地址和端口等属性;
      5、发送数据,用函数sendto();
      6、关闭网络连接;

Socket套接字网络编程

在一般的网络编程中,我们一般不会直接去操作TCP/IP协议的底层,而是用过socket套接字进行编程,他相当于一个TCP/IP与应用程序的中间层,通过套接字中提供的接口函数我们可以很快的上手网络开发。
接下来我们来了解一下socket中的一些常用函数:
. socket()函数

int socket(int family, int type, int protocol)
  1. family指明了协议族/域,通常AF_INET、AF_INET6、AF_LOCAL等;
  2. type是套接口类型,主要SOCK_STREAM、SOCK_DGRAM、SOCK_RAW;
  3. protocol一般取为0。成功时,返回一个小的非负整数值,与文件描述符类似。
  4. 返回值:非负描述符 – 成功,-1 - 出错

. bind()函数

int bind(int sockfd,const struct sockaddr* myaddr,socklen_t addrlen)
  1. sockfd是socket函数返回的描述符;
  2. myaddr指定了想要绑定的IP和端口号,均要使用网络字节序-即大端模式;
  3. addrlen是前面struct sockaddr(与sockaddr_in等价)的长度。
  4. 返回值:0 – 成功,-1 - 出错

. listen()函数

int listen(int sockfd, int backlog)
  1. sockfd是socket函数返回的描述符;
  2. backlog这个参数涉及到一些网络的细节。在进程正理一个一个连接请求的时候,可能还存在其它的连接请求。因为TCP连接是一个过程,所以可能存在一种半连接的状态,有时由于同时尝试连接的用户过多,使得服务器进程无法快速地完成连接请求。如果这个情况出现了,服务器进程希望内核如何处理呢?内核会在自己的进程空间里维护一个队列以跟踪这些完成的连接但服务器进程还没有接手处理或正在进行的连接,这样的一个队列内核不可能让其任意大,所以必须有一个大小的上限。这个backlog告诉内核使用这个数值作为上限。毫无疑问,服务器进程不能随便指定一个数值,内核有一个许可的范围。这个范围是实现相关的。很难有某种统一,一般这个值会小30以内。
  3. 返回值:0 – 成功,-1 - 出错

. accept()函数

int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);   
  1. sockfd, 利用系统调用socket()建立的套接字描述符,通过bind()绑定到一个本地地址(一般为服务器的套接字),并且通过listen()一直在监听连接;
  2. addr, 指向struct sockaddr的指针,该结构用通讯层服务器对等套接字的地址(一般为客户端地址)填写,返回地址addr的确切格式由套接字的地址类别(比如TCP或UDP)决定;若addr为NULL,没有有效地址填写,这种情况下,addrlen也不使用,应该置为NULL;
  3. addrlen, 一个值结果参数,调用函数必须初始化为包含addr所指向结构大小的数值,函数返回时包含对等地址(一般为服务器地址)的实际数值;
  4. 返回值:非负数– 成功,-1 - 出错.

. connect()函数

int connect(int sockfd,conststruct sockaddr *addr, socklen_t addrlen)    
  1. 通过此函数建立于TCP服务器的连接,实际是发起三次握手过程,仅在连接成功或失败后返回。参数sockfd是本地描述符,addr为服务器地址,addrlen是socket地址长度。
  2. UDP的connect函数,结果与tcp调用不相同,没有三次握手过程。内核只是记录对方的ip和端口号,他们包含在传递给connect的套接口地址结构中,并立即返回给调用进程。
  3. 返回值:非负数– 成功,-1 - 出错

. send()函数

int send( SOCKET s, const char FAR *buf, int len, int flags );
  1. 该函数的第一个参数指定发送端套接字描述符;
  2. 第二个参数指明一个存放应用程序要发送数据的缓冲区;
  3. 第三个参数指明实际要发送的数据的字节数;
  4. 第四个参数一般置0。

. recv ()函数

int recv( SOCKET s, char FAR *buf, int len, int flags);
  1. 该函数的第一个参数指定发送端套接字描述符;
  2. 第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;
  3. 第三个参数指明buf的长度;
  4. 第四个参数一般置0。

. sendto ()函数

int sendto( SOCKET s, const char FAR* buf, int len, int flags, const struct sockaddr FAR* to, int tolen)
  1. s:一个标识套接口的描述字。
  2. buf:包含待发送数据的缓冲区。
  3. len:buf缓冲区中数据的长度。
  4. flags:调用方式标志位。
  5. to:(可选)指针,指向目的套接口的地址。
  6. tolen:to所指地址的长度。

. recvfrom ()函数

int recvfrom( SOCKET s, char FAR* buf, int len, int flags)
  1. s:标识一个已连接套接口的描述字。
  2. buf:接收数据缓冲区。
  3. len:缓冲区长度。
  4. flags:调用操作方式。
  5. from:(可选)指针,指向装有源地址的缓冲区。
  6. fromlen:(可选)指针,指向from缓冲区长度值。

UDP网络聊天室实现

功能概述

利用socket编程基础实现一个基础的聊天室功能,对新成员的加入进行广播,同时具有群发和私聊两种聊天模式。

  1. 服务器端采用单线程工作模式,这种情况仅适合单一聊天室的数据服务。若要开启多个聊天室,可以使用多线程。
  2. 客户端 采用多线程编程模式,一个线程进行消息的接受,另一个线程实现用户输入和消息的发送。

服务器编程

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include <arpa/inet.h>#define MYPORT 8887#define ERR_EXIT(m) \do { \perror(m); \exit(EXIT_FAILURE); \} while (0)void echo_ser(int sock)
{}int main(void)
{int sock,portl,numb;char addrl[2048];if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)ERR_EXIT("socket error");struct sockaddr_in servaddr,peeraddr,peeaddr;memset(&servaddr, 0, sizeof(servaddr));//初始化清空数组memset(&peeaddr, 0, sizeof(peeaddr));char ipstr[128];/*初始化套接字结构体*/servaddr.sin_family = AF_INET;servaddr.sin_port = htons(MYPORT);servaddr.sin_addr.s_addr = htonl(INADDR_ANY);peeaddr.sin_family = AF_INET;printf("服务器启动\n",MYPORT);if (bind(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)ERR_EXIT("bind error");char recvbuf[2048] = {0};char addr[30][100];//用户ip列表int  port[30];//端口号数组char name[30][100];//用户名数组char *ip;socklen_t peerlen;int n,nu=0,lon,in=0,xx,check,chec;while (1){peerlen = sizeof(peeraddr);memset(recvbuf, 0, sizeof(recvbuf));n = recvfrom(sock, recvbuf, sizeof(recvbuf), 0,(struct sockaddr *)&peeraddr, &peerlen);46.//通篇程序唯一的接收函数。所有的刷新数据全部来自这里if(n!=0){printf("%s %d %s\n",ip=inet_ntop(AF_INET,(struct sockaddr *)&peeraddr.sin_addr.s_addr,ipstr,sizeof(ipstr)),portl=ntohs(peeraddr.sin_port),recvbuf);/*下面这部分用来做新用户进入控制,如果用户IP地址已经存在,说明此用户是中途退出后再进入的,就不在对用户数据进行添加,仅仅修改端口号就可以;如果ip地址是新的IP,那么创建新的数据列。存储新的连接信息。*/if (recvbuf[0]=='>'){if(nu==0) in=1;else{for(check=0;check<nu;check++){ //检测IP是否重复in=0;for(int mm=0;mm<13;mm++){if(ip[mm]!=addr[check][mm]){in=1; } }if(in==0)break;   //如果IP地址重复,立即跳出循环,此时的check的值就是重复的IP数组号        }}//printf("in %d\n",in);if(in==1){for(lon=0;lon<peerlen+1;lon++){addr[nu][lon]=ip[lon];name[nu][lon]=recvbuf[lon];}port[nu]=portl;// name[nu]=recvbuf;xx=nu;nu++;}else{port[check]=portl;xx=check;}printf("%s进入房间,IP:%s\n",name[xx],addr[xx]);for(int fnu=0;fnu<nu;fnu++){//向所有在线用户发送新用户进入的信息 peeaddr.sin_addr.s_addr = inet_addr(addr[fnu]);peeaddr.sin_port = htons(port[fnu]);printf("发送欢迎信息给: %s   %d\n",addr[fnu],port[fnu]);sendto(sock, recvbuf, 20, 0,(struct sockaddr *)&peeaddr, sizeof(peeaddr));}memset(recvbuf, 0, sizeof(recvbuf));}else if(n > 0){//如果接受的数据前面不包含>这说明不是新用户入列信息.printf("接收到的数据:%s\n",recvbuf);/*这一部分代码针对私聊信息进行处理,若果接受的信息包含@字符,这说明这是私聊*/if(recvbuf[0]=='@'){int mn;for(mn=0;mn<100;mn++){//获取私聊对象用户名if(recvbuf[mn]=='^') break;}for(numb=0;numb<nu;numb++){//遍历在线的用户名数组,如果匹配成功,就可以获得这个用户的数组号,从而得到他的全部连接信息int ig=1;for(int ii=1;ii<mn;ii++){if(recvbuf[ii]!=name[numb][ii]){ig=0;break;}}if(ig==1) break;}/*匹配成功,配置接收方socke信息*/peeaddr.sin_addr.s_addr = inet_addr(addr[numb]);peeaddr.sin_port = htons(port[numb]);for(chec=0;chec<nu;chec++){in=0;for(int mm=0;mm<13;mm++){if(ip[mm]!=addr[chec][mm]){in=1;}}if(in==0)break;          }printf("mn:%d chec %d\n",mn,chec);memset(addrl, 0, sizeof(addrl));for(int ad=0;ad<mn;ad++){addrl[ad]=name[chec][ad+1];}strcat (addrl,":");printf("%s发送信息给:%s\n",addrl,addr[numb]);strcat (addrl,recvbuf);sendto(sock, addrl, strlen(addrl), 0,(struct sockaddr *)&peeaddr, sizeof(peeaddr));}else{/*对于群发消息,这里开始循环发送信息给所有用户*/for(chec=0;chec<nu;chec++){in=0;for(int mm=0;mm<13;mm++){printf("%c %c\n",ip[mm],addr[chec][mm]);if(ip[mm]!=addr[chec][mm]){in=1;}}printf("%s \n",addr[chec]);if(in==0)break;          }for(int tt=0;tt<nu;tt++){printf("%s \n",addr[tt]);}for(int ad=0;ad<strlen(name[chec]);ad++){addrl[ad]=name[chec][ad+1];}strcat (addrl,":");printf(" %s发送信息:   %s\n",addrl,recvbuf);strcat (addrl,recvbuf);for(int fnu=0;fnu<nu;fnu++){printf("发送信息给:%s\n",addr[fnu]);peeaddr.sin_addr.s_addr = inet_addr(addr[fnu]);peeaddr.sin_port = htons(port[fnu]);sendto(sock, addrl, strlen(addrl), 0,(struct sockaddr *)&peeaddr, sizeof(peeaddr));printf(" %s\n",addrl);}             memset(addrl, 0, sizeof(addrl));}}}memset(recvbuf, 0, sizeof(recvbuf));}close(sock);return 0;
}

客户端编程

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <termios.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <pthread.h>#define MAX 10
#define MYPORT 8887
#define user ">winds"
#define ERR_EXIT(m) \do \
{ \perror(m); \exit(EXIT_FAILURE); \} while(0)char* SERVERIP = "192.168.1.100"; 
pthread_t thread[2];  //两个线程
pthread_mutex_t mut;
int number=0;
int i;
pthread_t id_1;
int sock;struct sockaddr_in servaddr;
pid_t pid;
int ret;
char sendbuf[1024] = {0};
char recvbuf[1024] = {0};
int flag=1;
char addr[30]={0};//线程一,这个线程负责循环接收信息并且显示出来。
void *thread1()
{while (flag){ret = recvfrom(sock, recvbuf, sizeof(recvbuf), 0, NULL, NULL);if(recvbuf[0]=='>'){printf("欢迎:%s 进入房间\n",recvbuf);}  else if(recvbuf[0]!='>'){printf("%s\n",recvbuf);} memset(recvbuf, 0, sizeof(recvbuf));memset(sendbuf, 0, sizeof(sendbuf));}close(sock);pthread_exit(NULL);
}//线程二,这个线程用来阻塞接收输入信息,并发送出去
void *thread2()
{// printf("thread2 : I'm thread 2/n");while (flag){printf("发送:%s\n",sendbuf);fgets(sendbuf, sizeof(sendbuf), stdin);sendto(sock, sendbuf, strlen(sendbuf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));memset(recvbuf, 0, sizeof(recvbuf));memset(sendbuf, 0, sizeof(sendbuf));}close(sock);pthread_exit(NULL);
}void thread_create(void)   //创建两个线程
{int temp;memset(&thread, 0, sizeof(thread));          /*创建线程*/if((temp = pthread_create(&thread[0], NULL, thread1, NULL)) != 0)     printf("线程1创建失败!/n");//else//printf("线程1被创建/n");if((temp = pthread_create(&thread[1], NULL, thread2, NULL)) != 0)  printf("线程2创建失败");//else// printf("线程2被创建/n");
}void thread_wait(void)
{/*等待线程结束*/if(thread[0] !=0){             //comment4    pthread_join(thread[0],NULL);printf("线程1已经结束/n");}if(thread[1] !=0) {  //comment5pthread_join(thread[1],NULL);printf("线程2已经结束/n");}
}int main()
{/*用默认属性初始化互斥锁*/pthread_mutex_init(&mut,NULL);printf("用户: %s\n",user);if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)ERR_EXIT("socket");memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(MYPORT);servaddr.sin_addr.s_addr = inet_addr(SERVERIP);sendto(sock,user,8,0,(struct sockaddr *)&servaddr, sizeof(servaddr)); //发送用户信息给服务器thread_create();thread_wait();return 0;
}

运行结果

在这里插入图片描述
这是用户进入房间时,服务器的显示情况,每一次一个新用户进入房间,服务器将会把该用户的用户名向所有在线用户发送一遍,如果该用户重复进入服务器只更新该用户的端口号,并且不再修改IP信息,也不会再添加新的用户信息组。
在用户发送消息时服务器端的提示内容:
在这里插入图片描述
手机端安装"手机CAPP"app即可运行客户端程序:
在这里插入图片描述

总结

遇到的问题

服务器编程

  1. 数组信息错乱:在客户端发送过长的信息时,会导系统崩溃,并且在进行用户名查找时,对用户数组进行赋值会导致个别用户IP地址丢失。这个现象在Deepin系统中表现的非常明显,然而再Ubuntu中并不会出现这个问题。
    原因:根据我的推测这应该是属于变量的内存溢出问题,程序定义变量的过程实质上是内存的分配过程,当变量长度不确定(使用指针开辟数组)这时系统会从该内存号开始分配空间给变量。如果一个变量和下一个变量内存空间是相邻的,一旦某一个变量数据溢出就会导致数据覆盖到下一个变量的内存空间。由此可以推断,Deepin采用的是连续内存分配,而ubuntu采用了分散内存分配。
    解决:在进行服务器编程的时候,我使用了几个用指针方式开辟的数组变量,因此他们的长度并不确定。这里改变他的定义方式,限制他们的大小。或者将他们定义的顺序改变一下,都可以解决这个问题。

客户端编程

  1. 多进程模式导致系统崩溃:在使用多进程模式的时候,我使用了while循环创建子进程监听用户输入和消息接受,代码如下:
 while (flag){ret = recvfrom(sock, recvbuf, sizeof(recvbuf), 0, NULL, NULL);pid = fork();if(pid == 0){if(recvbuf[0]=='>'){printf("欢迎:%s 进入房间\n",recvbuf);}  }else{if(recvbuf[0]!='>'){printf("%s\n",recvbuf);}  printf("发送:%s\n",sendbuf);fgets(sendbuf, sizeof(sendbuf), stdin);sendto(sock, sendbuf, strlen(sendbuf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));}memset(recvbuf, 0, sizeof(recvbuf));memset(sendbuf, 0, sizeof(sendbuf));}

这样一来程序可以正常执行,并且开始运行全部正常,但是再运行了几十条消息之后系统响应速度明显下降,最终只能强制关机。
原因:在函数fork()之后立即开始两个进程。分别执行fork=0子进程和fork=pid(子进程号)父进程。子进程会把整个程序资源和代码都复制一份,在另一个存储空间执行,它的资源将不再和父进程共享。
在我的这段代码中,在while语句里面创建了子程序,并且在子程序代码中没有while结束标志。这样一来子程序会一直在while创建子程序的子程序。每发送一条信息,或者每接收一条信息,都会创建一个子程序,以此维持对信息的不间断接收和对输入的阻塞等待。
但是!这样的程序是具有极大地弊端的。因为我们的子进程不会结束,并且不断创建新的子进程,当子进程创建下一个子进程后,上一个子进程其实已经没有作用了,但是他还在作为父进程维持当前的子进程,所以我们不能在父进程里面回收他的资源,但是如果加入子进程结束条件,则会导致无法持续监测接收数据。这就形成了一个两难之选:在这里我选择了牺牲系统资源。这样一来系统会出现非常多的僵尸进程。我们知道在系统中能够分配的进程号是有限的,一旦僵尸进程占用大量的进程号就会导致系统错乱,甚至崩溃。
比如著名的while-fork炸弹:

int main()  
{  while(1)  fork();  return 0;  
}  

你会发现这与我的代码结构十分相似,只不过这个语句是瞬间创造大量子进程崩溃你的系统,而我的代码是慢性崩溃你的系统。
解决:采用多线程方式实现客户端的代码设计;


  1. 关于IP地址的更多信息 ↩︎

  2. 这部分来自这位博主的博客 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/32987.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Linux下TCP/IP协议局域网聊天室

这几天一直在看TCP/IP这块的内容,写个简单socket通信demo,实现了多个客户端相互发送消息,以及服务端给多个客户端发送上线/下线消息 基本框架: server.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #inc…

第22节 NAT——实现公私有IP地址转换

NAT 1 NAT概述1.1 IP地址概述1.2NAT概述 2 NAT分类2.1 静态NAT2.2 动态NAT2.3 PAT2.4 静态PAT 3 NAT命令3.1 定义内外网接口3.2 配置PAT3.3 配置静态端口转换 4 路由器工作原理归纳完善5 总结 1 NAT概述 1.1 IP地址概述 ipv4地址使用现状&#xff1a;现在已严重不够用。仅ABC…

Linux_C_tcp/ip通信

目录 代码相互收发文本交互 遇到的问题 代码 相互收发 server代码 /********** 1、在服务器端接受消息时知道对方的IP和端口提示&#xff1a;bind出现&#xff1a;Address already in use 方法&#xff1a;netstat -nap查看 用kill -9 pid杀死 2、利用TCP实现文件传输 **…

法大大Luke:打造深度生态,实现联合创新

4月26日&#xff0c;国内领先的电子合同和电子签云服务平台法大大举办了以“数智‘签’引&#xff0c;万物生长”为主题的春季产品发布会&#xff0c;并推出全新一代数智化签约管理平台。该平台型产品经过2年半的调研分析及打磨验证&#xff0c;聚焦新的市场环境下企业、组织、…

在阿里6年,但今年这情况,劝大家还是多一手准备吧

大家期待的经济繁荣&#xff0c;没有来。 往年的金三银四&#xff0c;跳槽涨薪&#xff0c;也没有来。 来了的&#xff0c;是大公司裁员的消息频频爆出。 来了的&#xff0c;是ChatGPT&#xff0c;第一批受到影响的人已经失业了。 而且你有没有发现&#xff0c;它平时没什么…

【企业架构设计实战】大数据架构设计

目录 数据架构概述 什么是数据? 什么是数据架构

【企业架构设计实战】5 大数据架构设计

数据架构概述 什么是数据? 一个企业的数字化核心是数据,数据化的价值依赖于数据的标准和质量,数据对一个企业来说至关重要,它也是整个信息化建设及企业架构的核心。数据具有多样性,有结构化的、非结构化的,与业务相关的、与系统相关的,企业内部的、企业外部的等。 从数据…

找工作之前问问自己做好这些准备以及知道这些面试题的答案了吗?

根据回忆写下的面试要点&#xff0c;都是比较常见的问题。大家可以对照回答下&#xff0c;不清楚的可以查下资料补充下。 今年虽然疫情开放了&#xff0c;但是现在的Android开发的市场行情明显明显比之前稳定了许多&#xff0c;现在大厂疯狂裁员&#xff0c;小公司要求还挺高的…

OceanBase CTO杨传辉:放手去干,这行没有35岁危机

近日&#xff0c;OceanBase CTO 杨传辉做客 CSDN 《开谈&#xff1a;中国开源数据库新格局》栏目&#xff0c;中达金桥资深数据库专家卢东明对话杨传辉等中国领先数据库厂商从业者。对话开场&#xff0c;杨传辉给 OceanBase 打了 3 个标签&#xff1a;分布式、性价比、HTAP&…

GPT 大模型的应用路线图:可控性是最强路标 | The Roadmap of Generative AI

目录 生成式AI的应用路线图:可控性是最强路标 | The Roadmap of Generative AI 生成式AI的应用场景在哪里</

AI应用路线图:可控性是最强路标

生成式AI的可控性越强&#xff0c;对市场和产业的颠覆性就越大&#xff01; 作者 | 王咏刚、童超 责编 | 夏萌 生成式 AI 的应用场景在哪里 Stable Diffusion、ChatGPT等生成式AI技术&#xff08;Generative AI&#xff09;在2023年上半年吸引了IT创投圈的最多注意力。当我们稍…

抖音根据关键词取商品列表 API 返回值说明

请求参数&#xff1a;q连衣裙&page1&sort 参数说明&#xff1a;q:关键词, filter:搜索类型&#xff1a;filtervideo 搜索视频、filtergoods 搜索商品、filteruser 搜索用户, page:页数 sort:排序(目前只视频可排序):sortnew 最新发布 sortcredit 最多点赞 sortbid 综合…

简单对接抖音小店的接口

最近公司需要对接抖音小店的接口。然后其实对接起来还是蛮简单的&#xff0c;不过自己阅读文档的能力还有点问题&#xff0c;所以这里记录一下开发遇到的问题。 文档地址&#xff1a;https://op.jinritemai.com/docs/guide-docs/6/14 首先是需要准备的配置。 抖音小店的整个流…

获得抖音商品详情 API 返回值说明

请求地址: https://api-gw.onebound.cn/douyin/item_get 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_sear…

抖音关键词月搜查询( API 返回值说明)

为了进行电商平台API开发&#xff0c;我们需要做下面几件事情。 1&#xff09;开发者注册一个账号 2&#xff09;然后在平台应用注册一个应用程序键&#xff08;App Key) 。 3&#xff09;下载平台API的SDK并掌握基本的API基础知识和调用 4&#xff09;利用SDK接口和对象&a…

抖音跳转微信加好友功能实现解析

抖音现在毫无疑问的成为了大众喜闻乐见、爱不释手的娱乐利器&#xff0c;工作闲暇、茶余饭后、候车排队等等只要有空&#xff0c;就会随时随刻随手划拉&#xff0c;每个人都沉浸在这虚拟和现实的交互之中&#xff0c;乐不思蜀&#xff0c;忘乎所以&#xff0c;不能自拔。 抖音…

研究抖音的,点进来

作者&#xff1a;杨浩 全文共 5183 字&#xff0c;阅读需要 11 分钟 ———— / BEGIN / ———— 抖音之火&#xff0c;我们可能从主观上会听到很多声音&#xff0c;比如&#xff1a;“中毒了&#xff0c;我每天晚上要刷2个小时”&#xff0c;、昨晚刷到凌晨4点”、“我家小女…

获取详情API接口(抖音)

API接口名称&#xff1a; item_get - 获得抖音商品详情 响应参数 Version: Date: 名称类型必须示例值描述itemitem[]0宝贝详情数据 注册申请试用&#xff1a; 点击注册 请求参数&#xff1a;num_iid3514453298386183303 参数说明&#xff1a;num_iid:抖音商品ID 请求示例…

清爽聊天无多余功能!抖音聊天工具上线

&#x1f447;&#x1f447;关注后回复 “进群” &#xff0c;拉你进程序员交流群&#x1f447;&#x1f447; 来源丨电脑报 https://mp.weixin.qq.com/s/iRwO_iot8DSfN5PZbbKMDA 近日&#xff0c;抖音在官网上线了一款桌面端聊天软件“抖音聊天”&#xff0c;将支持 windows 7…

今日推荐一款实用的搜题小程序,题多多搜题

为什么要用小程序 1、不用安装&#xff0c;即开即用&#xff0c;节省流量&#xff0c;节约安装时间&#xff0c;而且不占用桌面&#xff1b; 2、功能上更为集中、单一&#xff0c;降低用户的使用难度&#xff0c;减少手机的过度使用。 小程序怎么找 现在大厂都已经推出了各…