Linux:网络编程之TCP/IP模型,UDP协议

news2024/12/27 12:56:56

一、OSI模型七层结构

  OSI(Open Systems Interconnection)模型,即开放系统互连参考模型,是一个概念性框架,用于促进全球通信。它定义了网络通信的七层结构,每一层都执行特定的功能,并且每一层都使用下一层提供的服务,同时向它的上一层提供服务。这七层从下到上依次是:

  1. 物理层(Physical Layer)
    • 功能:定义物理设备之间如何传输原始比特流(0和1)。它定义了物理连接的特性,如电气规范、机械特性、功能和过程特性等。例如,以太网和光纤都是物理层的实现。
    • 例子:双绞线、同轴电缆、光纤、无线电波等物理传输介质;传输速率如100Mb/s、1Gb/s、10Gb/s等。
  2. 数据链路层(Data Link Layer)
    • 功能:数据链路层在物理层之上,负责将原始的比特流封装成帧(Frame),并提供错误检测和修正功能,确保数据的可靠传输。这一层还负责在物理网络中识别设备地址(如MAC地址)。
    • 例子:以太网(Ethernet)、帧中继(Frame Relay)、PPP(点对点协议)等;交换机工作在数据链路层。
  3. 网络层(Network Layer)
    • 功能:负责将数据包(Packet)从源端传输到目的端,可能跨越多个网络。
    • 例子:IP(Internet Protocol)协议;路由选择、流量控制、错误处理以及网络互联等功能;NAT(网络地址转换)也是网络层的一个功能。
  4. 传输层(Transport Layer)
    • 功能:为端到端的通信提供可靠的传输服务,确保数据包的顺序传输和完整性。
    • 例子:TCP(传输控制协议,提供面向连接的、可靠的传输服务)和UDP(用户数据报协议,提供无连接的、不可靠的传输服务,低延迟)。
  5. 会话层(Session Layer)
    • 功能:在两个通信的应用进程之间建立、管理和终止会话,管理通信双方之间的对话控制。
    • 例子:会话管理,如建立检查点、同步等;虽然具体协议不如低层那么知名,但它负责在网络应用之间建立和维护连接。
  6. 表示层(Presentation Layer)
    • 功能:对数据进行转换、加密和压缩,以便在应用层之间传输。
    • 例子:数据压缩(如gzip)、加密/解密(如SSL/TLS中的加密)、数据格式转换(如ASCII与EBCDIC之间的转换)。
  7. 应用层(Application Layer)
    • 功能:为用户的应用程序(如Web浏览器、电子邮件客户端等)提供网络服务。
    • 例子:HTTP(用于Web通信)、FTP(文件传输协议)、SMTP(简单邮件传输协议)、TFTP(简单文件传输协议)、DNS(域名系统)等。
  • NAT(网络地址转换) 是网络层的一个功能,用于解决IPv4地址不足的问题,通过在网络边界将私有IP地址转换为公网IP地址。

OSI模型为网络通信提供了一个标准化的框架,尽管在实际应用中,TCP/IP协议栈(包含四层:网络接口层、网络层、传输层和应用层)更为广泛地被采用。然而,OSI模型仍然是理解网络通信原理的重要基础。

二、TCP/IP模型  

网际互联模型   ==》分为4层:
      实用模型  ===》工业标准
   也称tcp/ip协议栈
        

1. 应用层(Application Layer)

  • 职责:提供网络服务给最终用户,支持各种应用程序,如电子邮件、网页浏览、文件传输等。
  • 协议:HTTP(用于网页浏览)、FTP(文件传输协议)、SMTP(简单邮件传输协议)、DNS(域名系统)等。
  • 特点:应用层是TCP/IP协议栈中的最高层,为应用程序提供了接口,允许用户直接访问和使用网络服务。

2. 传输层(Transport Layer)

  • 职责:提供端到端的数据传输服务,确保数据的可靠性、顺序性和流量控制。
  • 协议:TCP(传输控制协议)和UDP(用户数据报协议)。
  • 特点:TCP协议提供可靠的、面向连接的数据传输服务,通过“三次握手”建立连接;UDP协议则提供无连接的数据传输服务,不保证数据的可靠性,但速度较快。

3. 网络层(Network Layer)

  • 职责:处理来自传输层的分组,将分组封装成数据包(IP数据包),并为数据包进行路径选择,最终将数据包从源主机发送到目的主机。
  • 协议:IP(网际协议)、ICMP(互联网控制消息协议)、IGMP(互联网组管理协议)、ARP(地址解析协议)等。
  • 特点:网络层负责数据包的路由和转发,确保数据包能够跨越不同的网络区域,从源主机准确地到达目的主机。

4. 接口层(Interface Layer,也称为网络接口层或数据链路层)

  • 职责:负责将数据包从物理介质发送到网络上的其他设备,处理物理地址(MAC地址)和数据帧的格式。
  • 协议:以太网、WiFi、PPP(点对点协议)等。
  • 特点:接口层是TCP/IP模型中最底层的一层,它直接与物理网络相连,负责数据的实际传输过程。它使用各种物理网络协议来确保数据帧在物理介质上的可靠传输。

TCP/IP协议与七层ISO模型的对应关系,大致如下图所示:

                    图:TCP/IP协议与七层ISO模型的对应关系​​​​​​​

DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)是一种网络协议,用于在局域网(LAN)中自动配置设备的网络参数。DHCP 允许网络中的设备(如计算机、打印机、智能手机等)自动从DHCP服务器获取其IP地址、子网掩码、默认网关和DNS服务器地址等网络配置信息,而无需手动配置这些信息。这样做的好处包括简化网络管理、减少配置错误、支持移动设备在网络中的无缝移动等。

三、TCP/IP协议族

一、应用层 (Application Layer)

  • HTTP: 超文本传输协议,用于Web浏览器和服务器之间的通信。
  • TFTP: 简单文件传输协议,一种简单的文件传输协议,主要用于在局域网中传输文件。
  • FTP: 文件传输协议,用于在网络上进行文件的双向传输。
  • SNMP: 简单网络管理协议,用于网络管理,如设备发现、性能监控等。
  • DNS: 域名系统,用于将域名(如www.taobao.com)解析为IP地址(如192.168.0.19,但通常不会是私有地址,而是公网地址)。

二、传输层 (Transport Layer)

  • TCP: 传输控制协议,一种面向连接的、可靠的、基于字节流的传输层通信协议。
  • UDP: 用户数据报协议,一种无连接的、不可靠的传输层协议。
  • 56k猫: 这不是一个传输层协议,而是指早期的调制解调器(Modem)的速率,用于通过电话线进行低速的数据传输。

三、网络层 (Network Layer)

  • IP: 互联网协议,负责数据包的路由和传输。
  • ICMP: 互联网控制消息协议,用于发送控制消息,如网络不通时发送的错误消息(ping命令就使用了ICMP协议)。
  • RIP: 路由信息协议,一种基于距离向量的内部网关协议(IGP),用于在小型网络中交换路由信息。
  • OSPF: 开放式最短路径优先,一种基于链路状态的内部网关协议,用于在大型和复杂网络中计算最佳路径。
  • IGMP: 互联网组管理协议,用于IP多播(Multicast)的管理。

四、物理层和数据链路层 (Physical Layer and Data Link Layer)

  • ARP: 地址解析协议,用于将网络层地址(如IP地址)解析为链路层地址(如MAC地址)。
  • RARP: 逆地址解析协议,用于无盘工作站等设备的网络启动,现已较少使用。
  • 注意:您提到的“物理层:ARP RARP ... ip--->mac”实际上是不准确的。ARP和RARP工作在数据链路层,而不是物理层。物理层关注的是实际的信号传输,如电信号或光信号。

ip4地址的分类

IP地址的分类主要基于其网络ID的不同,可以分为A类、B类、C类、D类和E类五大类。在点分十进制的表示方法中,IP地址是一个32位的二进制数,通常被分割为4个8位二进制数(也就是4个字节),每个字节的十进制取值范围是0-255,各字节之间用点(.)分隔。以下是各类IP地址的详细分类及特点:

1. A类IP地址

  • 网络地址范围:1.0.0.0 - 126.255.255.255(二进制表示为:00000001 00000000 00000000 00000000 - 01111110 11111111 11111111 11111111)
  • 特点
    • 网络号占1个字节,即前8位,最高位必须是“0”。
    • 第一个字节的范围是1-126(注意,0和127有特殊用途,不用于指派)。
    • 可用的A类网络有126个(2^7-2,因为网络号不能是全0或全1)。
    • 每个网络理论上可以支持的主机数为2^24-2(主机号不能是全0或全1)。
    • 适用于具有大量主机的大型网络。

2. B类IP地址

  • 网络地址范围:128.0.0.0 - 191.255.255.255(二进制表示为:10000000 00000000 00000000 00000000 - 10111111 11111111 11111111 11111111)
  • 特点
    • 网络号占2个字节,即前16位,最高两位必须是“10”。
    • 第一个字节的范围是128-191。
    • 可用的B类网络有16382个(2^14-2)。
    • 每个网络理论上可以支持的主机数为2^16-2。
    • 适用于中等规模的网络。

3. C类IP地址

  • 网络地址范围:192.0.0.0 - 223.255.255.255(二进制表示为:11000000 00000000 00000000 00000000 - 11011111 11111111 11111111 11111111)
  • 特点
    • 网络号占3个字节,即前24位,最高三位必须是“110”。
    • 第一个字节的范围是192-223。
    • C类网络数量较多,可达209万余个。
    • 每个网络理论上可以支持的主机数为254(2^8-2)。
    • 适用于小型网络,如局域网和校园网。

4. D类IP地址

  • 网络地址范围:224.0.0.0 - 239.255.255.255
  • 特点
    • 最高四位是“1110”,用于多播(Multicast)地址,不指向特定的网络。
    • 这类地址被用在多点广播中,用来一次寻址一组计算机。

5. E类IP地址

  • 网络地址范围:240.0.0.0 - 255.255.255.255
  • 特点
    • 最高四位是“1111”,保留为将来使用。
    • 主要用于Internet试验和开发。

*四、网络编程之UDP

 UDP中文称为:用户数据报

1、UDP的特点

  1. 无连接:UDP在发送数据之前不需要建立连接,发送方和接收方之间不存在持久的连接状态。(理解:每次链接的路径不一样)
  2. 不可靠:UDP不保证数据包的顺序、完整性或正确性。数据包可能会丢失、重复或乱序到达。
  3. 面向数据报:UDP以数据报的形式发送数据,每个数据报都被视为一个独立的单元,且UDP本身不提供数据重组的功能。
  4. 开销小:由于UDP没有复杂的连接建立和错误控制机制,因此其头部开销较小,数据传输效率较高。

1、特性: 无链接  不可靠  大数据   

2、框架: C/S模式 

   server:socket() ===>bind()===>recvfrom()===>close()
   client:socket() ===>bind()===>sendto() ===>close()

编写流程

2、socket()函数

 socket() 函数是 Unix/Linux 系统中用于创建新的套接字(socket)的一个系统调用。套接字是网络通信中的一个端点,它允许两个或多个进程(可能位于不同的计算机上)通过网络进行通信。socket() 函数用于初始化一个套接字,并返回一个与该套接字关联的文件描述符(file descriptor),该描述符随后可用于进一步的套接字操作,如绑定地址、监听连接、接受连接、发送和接收数据等。

#include <sys/types.h>          // 对于某些系统可能需要  
#include <sys/socket.h>  
  
int socket(int domain, int type, int protocol);
  • domain:指定协议族。常用的有 AF_INET(IPv4 地址)和 AF_INET6(IPv6 地址)。AF 代表“Address Family”。
  • type:指定套接字类型。对于 UDP,UDP的类型是 SOCK_DGRAM,表示数据报套接字。SOCK_STREAM 是用于 TCP 的套接字类型。
  • protocol:通常设置为 0,让系统自动选择该域(domain)和类型(type)下的默认协议。但在某些特殊情况下,可以指定特定的协议。

返回值:如果成功,socket() 返回一个非负的文件描述符,该文件描述符可以用于后续的套接字操作。如果失败,返回 -1,并设置 errno 以指示错误类型。

   3、bind()函数

bind() 函数是在网络编程中非常关键的一个函数,它用于将套接字(socket)与特定的IP地址和端口号绑定。

#include <sys/socket.h>  
  
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd 是由 socket() 函数返回的套接字文件描述符。
  • addr 是一个指向 sockaddr 结构的指针,该结构包含了IP地址和端口号等信息。根据IPv4或IPv6的不同,这个结构可能是 sockaddr_in 或 sockaddr_in6 类型。
  • addrlen 是 addr 参数所指向的结构的长度,这个长度通常是 sizeof(struct sockaddr_in) 或 sizeof(struct sockaddr_in6)

 如果 bind() 函数调用成功,它返回0;如果失败,则返回-1,并设置全局变量 errno 以指示错误的原因。

      bind() 客户端是可选的,服务器端是必选的。

4、sendto()函数

sendto() 函数是在网络编程中用于发送数据到指定的网络地址(IP地址和端口号)的函数。

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

功能:用于UDP协议中向对方发送数据。 

  • sockfd 是要发送数据的套接字的文件描述符。
  • buf 指向包含要发送数据的缓冲区的指针。
  • len 是要发送的数据的字节数。
  • flags 可以通过它来指定额外的选项,但对于大多数应用来说,通常设置为0。
  • dest_addr 是一个指向 sockaddr 结构的指针,该结构包含了目标地址的信息(IP地址和端口号)。根据IPv4或IPv6的不同,这个结构可能是 sockaddr_in 或 sockaddr_in6 类型。
  • addrlen 是 dest_addr 参数所指向的结构的长度,通常是 sizeof(struct sockaddr_in) 或 sizeof(struct sockaddr_in6)

如果 sendto() 函数调用成功,它返回发送的字节数。如果失败,则返回-1,并设置全局变量 errno 以指示错误的原因。

对于UDP套接字来说,sendto() 是发送数据包的常用方式,因为它允许程序直接指定数据的目的地。在TCP套接字中,虽然 sendto() 可以被调用,但它通常被 send() 或 write() 替代,因为TCP是一个面向连接的协议,其套接字已经与一个特定的远程地址和端口建立了连接。

需要注意的是,由于UDP是无连接的,因此每个 sendto() 调用都独立地发送一个数据包,并且接收方可能会以不同的顺序或根本不接收这些数据包(例如,由于网络拥塞或错误)。

5、recvfrom()函数

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

功能:用于UDP协议中获取对方发送的数据。

  • sockfd 是要接收数据的套接字的文件描述符。
  • buf 指向一个缓冲区,该缓冲区用于存储接收到的数据。
  • len 是缓冲区 buf 的大小,即最多可以接收的字节数。
  • flags 可以通过它来指定额外的选项,但对于大多数应用来说,通常设置为0。
  • src_addr 是一个指向 sockaddr 结构的指针,该结构用于存储发送数据包的源地址信息(如果调用者关心这一点的话)。这个参数可以设置为NULL,如果不需要源地址信息。
  • addrlen 是一个指向socklen_t变量的指针,该变量在调用前应该包含 src_addr 缓冲区的大小(如果 src_addr 不是NULL的话)。在调用返回时,它将包含实际存储在 src_addr 中的地址的实际大小。

如果 recvfrom() 函数调用成功,它返回接收到的字节数。如果连接被对方正常关闭,则返回0。如果发生错误,则返回-1,并设置全局变量 errno 以指示错误的原因。

对于UDP套接字来说,recvfrom() 是接收数据包的常用方式,因为它不仅接收数据,还提供了数据包的源地址信息。这使得UDP程序能够区分来自不同源的数据包,并据此作出响应。

需要注意的是,由于UDP是无连接的,因此 recvfrom() 可能会以不同的顺序接收数据包,或者根本不会接收某些数据包(例如,由于网络拥塞或错误)。

练习:

服务器代码:接收客户端的数据,并打印,再把接收到的数据发送给客户端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
typedef struct sockaddr* (SA);
int main(int argc, const 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=inet_addr("192.168.0.117");
	int ret=bind(sockfd,(SA)&server,sizeof(server));
	if(-1==ret)
	{
		perror("bind");
		exit(1);
	}
	while(1)
	{
		char buf[1024]={0};
		socklen_t len=sizeof(client);
		recvfrom(sockfd,buf,sizeof(buf),0,(SA)&client,&len);

		printf("%s\n",buf);
		time_t tm;
		time(&tm);
		sprintf(buf,"%s %s",buf,ctime(&tm));
		sendto(sockfd,buf,strlen(buf),0,(SA)&client,sizeof(client));
	}
	
	return 0;
}

客户端:向服务器发送数据,再接收服务器发送过来的数据并打印出来

#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
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;

    }
    //set ip port  man 7 ip 
    struct sockaddr_in server;
    bzero(&server,sizeof(server));
    server.sin_family  = AF_INET;
    server.sin_port  = htons(50000);// >50000 host to net short 
    server.sin_addr.s_addr = inet_addr("192.168.203.128");
    
    while(1)
    {
        char buf[1024]="hello,this udp test";
        sendto(sockfd,buf,strlen(buf),0,(SA)&server,sizeof(server));
        bzero(buf,sizeof(buf));
        recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL);
        printf("server:%s",buf);
        fflush(stdout);
        sleep(1);
    }
    return 0;
}

基于UDP的聊天室程序

将以上知识点融合,考虑如何实现一个基于UDP的聊天室程序。
    要求如下:
    1、要有注册过程,每个客户端必须在服务器端有注册信息。
    2、任意客户端发送的消息必须由服务器转发给所有在线客户端。
    3、任意客户端下线必须通知其他在线用户主机。
 

服务器:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
typedef struct sockaddr * (SA);
typedef enum {LOGIN,CHAT,LOGOUT}TYPE;
#define MAX 10
typedef struct 
{
    TYPE type;
    char buf[128];
    char client[50];
}MSG;
typedef struct 
{

    char name[50];
    struct sockaddr_in cli;
    int flag;
}LIST;
LIST list[MAX]={0};
int do_login(int sockfd, MSG* msg,struct sockaddr_in* cli)
{
    int i = 0 ;// 把刚刚登陆的客户端信息存放在服务器
    for(i = 0 ;i<MAX;i++)
    {
        if(0 == list[i].flag)
        {
            list[i].flag = 1;
            strcpy(list[i].name ,msg->client);
            memcpy(&list[i].cli,cli,sizeof(struct sockaddr_in));
            break;
        
        }
    }
    strcpy(msg->buf,"上线了");
    //转发新客户端上线信息,给其他客户段
    for(i = 0;i<MAX;i++)
    {
        if(1 ==list[i].flag && 0!=memcmp(&list[i].cli,cli,sizeof(struct sockaddr_in)))
        {
            sendto(sockfd,msg,sizeof(MSG),0,(SA)&list[i].cli,sizeof(list[i].cli));
        }
    }
    return 0;
}
int do_chat(int sockfd, MSG* msg,struct sockaddr_in*cli)
{
    int i =0;
    for(i = 0;i<MAX;i++)
    {
        if(1 ==list[i].flag && 0!=memcmp(&list[i].cli,cli,sizeof(struct sockaddr_in)))
        {
            sendto(sockfd,msg,sizeof(MSG),0,(SA)&list[i].cli,sizeof(list[i].cli));
        }
    }

    return 0;

}
int do_logout(int sockfd,MSG*msg,struct sockaddr_in* cli)
{

    strcpy(msg->buf,"要走了");
    int i = 0 ;
    for(i=0;i<MAX;i++)
    {
        if(1 == list[i].flag && 0 == memcmp(&list[i].cli,cli,sizeof(struct sockaddr_in)))
        {
            list[i].flag = 0 ;
        }
        else if(1 == list[i].flag && 0 != memcmp(&list[i].cli,cli,sizeof(struct sockaddr_in)))
        {
            sendto(sockfd,msg,sizeof(MSG),0,(SA)&list[i].cli,sizeof(list[i].cli));
        }
    }
    return 0;
}
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 
    struct sockaddr_in server,client;
    bzero(&server,sizeof(server));
    bzero(&client,sizeof(client));
    server.sin_family  = AF_INET;
    server.sin_port  = htons(50000);// >50000 host to net short 
    server.sin_addr.s_addr =INADDR_ANY;
    int ret = bind(sockfd,(SA) &server,sizeof(server));
    if(-1 == ret)
    {
        perror("bind");
        exit(1);
    }
    while(1)
    {
        MSG msg;
        bzero(&msg,sizeof(msg));
        socklen_t len = sizeof(client);
        recvfrom(sockfd,&msg,sizeof(msg),0,(SA)&client,&len);
        switch(msg.type)
        {
        case LOGIN:
            do_login(sockfd,&msg,&client);
            break;
        case LOGOUT:
            do_logout(sockfd,&msg,&client);
            break;
        case CHAT:
            do_chat(sockfd,&msg,&client);
            break;
            default:
            do_logout(sockfd,&msg,&client);
        }
    }
    return 0;
}

发送端:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
#include <pthread.h>
typedef struct sockaddr * (SA);
typedef enum {LOGIN,CHAT,LOGOUT}TYPE;
typedef struct 
{
    TYPE type;
    char buf[128];
    char client[50];
}MSG;
void* th1(void* arg)
{
    int sockfd = *(int*)arg;
    MSG msg;
    while(1)
    {
        bzero(&msg,sizeof(msg));
        recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL);
        printf("%s:%s\n",msg.client,msg.buf);
    }

}
typedef struct 
{
    char name[50];
    int sockfd;
    struct sockaddr_in ser;
}TH_ARG;
void * th2(void* arg)
{
    
    TH_ARG* tmp =  (TH_ARG* )arg;
    int sockfd=tmp->sockfd;

    MSG msg;
    int run_flag = 1;
    while(run_flag)
    {
        bzero(&msg,sizeof(msg));
        printf("to all:");

        fgets(msg.buf,sizeof(msg.buf),stdin);
        msg.buf[strlen(msg.buf)-1]='\0';
        if(0 == strcmp("#quit",msg.buf))
        {
            msg.type =LOGOUT;
            run_flag = 0;
        }else
        {
            msg.type = CHAT;
        }
        strcpy(msg.client,tmp->name);
        sendto(sockfd,&msg,sizeof(msg),0,(SA)&tmp->ser,sizeof(tmp->ser));
    }
    exit(1);
    return 0;
}
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 
    struct sockaddr_in server;
    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;
    

    MSG msg;
    bzero(&msg,sizeof(msg));

    printf("input name:");
    char name[50]={0};
    fgets(name,sizeof(name),stdin);
    name[strlen(name)-1]='\0';
    strcpy(msg.client,name);
    msg.type  = LOGIN;

    
    sendto(sockfd,&msg,sizeof(msg),0,(SA)&server,sizeof(server));
    TH_ARG arg;
    bzero(&arg,sizeof(arg));
    arg.sockfd = sockfd;
    strcpy(arg.name ,name);
    arg.ser = server;// memcpy 

    pthread_t tid1,tid2;
    pthread_create(&tid1,NULL,th1,&sockfd);
    pthread_create(&tid2,NULL,th2,&arg);

    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

25考研人数预计下降?这一届考研有哪些新趋势?

2025年考研时间线&#xff1a; 2024年9月&#xff1a;公共课及各院校考试大纲公布&#xff1b; 2024年9月下旬&#xff1a;预报名&#xff1b; 2024年10月&#xff1a;正式报名&#xff1b; 2024年11月&#xff1a;线上/线下确认&#xff1b; 2024年12月中下旬&#xff1a…

腾讯版GPT-4o平替方案:VITA

引言 庙内无僧风扫地&#xff0c;寺中少灯月照明。 小伙伴们好&#xff0c;我是微信公众号《小窗幽记机器学习》的小编&#xff1a;买黑神话的小男孩&#xff0c;紧接卖黑神话的小女孩的小作文&#xff0c;今天这篇小作文主要介绍腾讯开源(截至2024年8月25日尚未真正开源&…

【软考】数字签名

目录 1. 说明2. 过程2.1 数字签名过程2.2 数字加密过程 3. 公开密钥4. 报文加密5. 例题5.1 例题1 1. 说明 1.书信或文件是根据亲笔签名或印章来证明其真实性。2.在计算机网络中传送的文电用数字签名来解决问题。3.数字签名必须保证三点&#xff1a;接收者能够核实发送者对报文…

[C语言]第八节 数组一基础知识到高级技巧的全景探索

目录 8.1 数组概念的引入 8.2.⼀维数组的创建和初始化 8.2.1 数组的创建 8.2.2数组的初始化 8.2.3 数组的类型 8.3 ⼀维数组的使⽤ 8.3.1 数组下标 8.3.2 打印数组元素 8.3.3 输入数组元素 8.4 ⼀维数组在内存中的存储 8.5 sizeof计算数组元素个数 8.5.1 sizeof 关键…

第4章-05-用WebDriver下载页面csv到本地

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年CSDN全站百大博主。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已收录于专栏:Web爬虫入门与实战精讲,后续完整更新内容如下。 文章…

Java 入门指南:Java 并发编程 —— JMM Java内存模型

JMM&#xff08;Java Memory Model&#xff0c;Java 内存模型&#xff09;&#xff08;抽象模型&#xff09;是用来描述和控制多线程之间内存可见性、有序性、原子性、指令重排等问题的规范。 JMM 定义了一组规则&#xff0c;规定了在多线程环境下&#xff0c;线程在执行共享变…

尚品汇-MQ模块搭建测试、消息不丢失(重)(四十三)

目录&#xff1a; &#xff08;1&#xff09;消息不丢失 &#xff08;2&#xff09;消息确认 &#xff08;3&#xff09;消息确认业务封装 &#xff08;4&#xff09;封装发送端消息确认 &#xff08;5&#xff09;封装消息发送 &#xff08;6&#xff09;发送确认消息测试…

【C#】Visual Studio 2017开发C#,按F1键没有跳转到C#帮助文档,反而跳到了Qt的帮助文档

1. 原因 Visual Studio中安装了Qt的插件&#xff0c;所以将F1的跳转链接转到了Qt的帮助文档。 2. F1改回微软帮助文档方法 工具 - 选项 - Qt - General - Try Qt Documentation when F1 is pressed改为Flase

Web服务端通过SSE推送消息给浏览器客户端的实现方案(附详细代码和仓库地址)

目录 1、SSE&#xff08;Server-Sent Events&#xff09;简介2、SSE 的工作原理3、SSE 与客户端轮询的区别和优势比较区别优势 4、SSE简单实现(单机应用Demo)演示效果SSE-Demo仓库地址下面直接贴代码&#xff1a;前端实现&#xff1a;后端实现&#xff1a; 5、SSE简单实现(分布…

【pycharm】汉化及翻译插件

汉化插件 翻译插件 使用 选中右键翻译

一键解决LBP2900通信错误的问题(同样支持Win 11系统)

**目录** **前言****常见解决方式****方案一&#xff1a;端口排除****方案二&#xff1a;服务重启****方案三&#xff1a;注册表注入修复** 前言 佳能LBP2900向来是经典耐用款的打印机。想必各位可能遇到过&#xff0c;由于老旧会出现奇葩的问题&#xff0c;譬如 就算USB接口已…

【C++篇】~类和对象(上)

【C篇】 类和对象上 一类二实例化内存对齐原因&#xff08;用空间换时间&#xff0c;提高效率&#xff09; 一类 ‘类’class可以理解为C语言阶段的‘结构体’&#xff0c;它的用法与struct大差不差很多地方都相同&#xff0c;但是C毕竟是C&#xff0c;类的用法肯定比结构体的…

Linux Kernel 6.12版预计将支持在崩溃后显示二维码 后续可以解码排查错误

7 月份时红帽工程师基于 systemd 255 版的全屏显示错误消息功能为 Linux Kernel 开发崩溃后显示二维码选项&#xff0c;这与微软在 Windows 10/11 蓝屏死机后显示二维码有异曲同工之妙。 不过 Linux 与 Windows 在崩溃时显示的二维码内容则有本质区别&#xff0c;因为 Window…

单链表反转(C语言)

1 问题描述 力扣&#xff08;LeetCode&#xff09;--反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 例如&#xff1a; 输入&#xff1a;head [1,2,3,4,5]输出&#xff1a;[5,4,3,2,1] 输入&#xff1a;head [1,2]输出&#x…

11 Java 方法引用、异常处理

文章目录 前言一、Java接口之函数式编程 --- 接口知识补充1 Function<T,R>泛型接口2 BiFunction<T, U, R>泛型接口3 自定义泛型函数式编程接口 二、方法引用1 方法引用初体验&#xff08;以Array.sort()方法为例&#xff09;2 引用静态方法3 引用其他类成员方法 前…

【面试五】PID控制算法

一、 PID算法简介 PID&#xff08;Proportional-Integral-Derivative&#xff09;控制算法是一种经典的反馈控制方法&#xff0c;广泛应用于自动控制系统&#xff0c;例如温度控制、速度控制、位置控制等。 PID控制算法的核心包含三个部分&#xff1a;比例项&#xff08;P&…

@antv/g6 业务场景:流程图

1、流程图是流经一个系统的信息流、观点流或部件流的图形代表。在企业中&#xff0c;流程图主要用来说明某一过程。这种过程既可以是生产线上的工艺流程&#xff0c;也可以是完成一项任务必需的管理过程。业务场景流程图如下&#xff1a; 2、绘制流程图的 Tips 流程图一般是用…

计算机毕业设计选题推荐-果树生长信息管理系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

Redis三种集群模式:主从模式、哨兵模式和Cluster模式

1. 总结经验 redis主从&#xff1a;可实现高并发(读)&#xff0c;典型部署方案&#xff1a;一主二从 redis哨兵&#xff1a;可实现高可用&#xff0c;典型部署方案&#xff1a;一主二从三哨兵 redis集群&#xff1a;可同时支持高可用(读与写)、高并发&#xff0c;典型部署方…

探索Python数据持久化的秘密:ZODB库的神奇之旅

文章目录 探索Python数据持久化的秘密&#xff1a;ZODB库的神奇之旅背景ZODB是什么&#xff1f;如何安装ZODB&#xff1f;简单库函数使用方法场景应用常见Bug及解决方案总结 探索Python数据持久化的秘密&#xff1a;ZODB库的神奇之旅 背景 在Python的广阔世界中&#xff0c;数…