欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

网络编程--TCP/UDP 通信模型

程序员文章站 2024-02-29 20:55:16
...

网络编程模型


网络编程--TCP/UDP 通信模型

上述模型中,每个概念的含义如下:

  1. Socket: 建立 Socket。创建一个 Socket 描述符;
  2. bind: 用于服务器端,把 Socket 的描述符与协议类型、本地IP、本地端口等信息进行绑定;
  3. listen: 用于服务器端,主要用于监听来自外部的连接,可以设置最大允许外部连接的数量;
  4. connect: 用于客户端,向服务器发起连接;
  5. accept: 用于服务器,接收客户端的连接请求。此时会返回一个与该客户端对应的新的 Socket 描述符,与该客户端的通信使用此 Socket 的描述符;
  6. send/sendto: 通过 Socket 的发送数据;
  7. recv/recvfrom: 通过 Socket 的接收数据;
  8. 关闭 Socket 的。

主要函数详解


建立套接字 socket()


网络编程--TCP/UDP 通信模型

常用实例为:

/*创建IPv4 TCP Socket*/
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == sfd) {
    perror("socket");
    exit(-1);
}

绑定地址 bind()


bind() 绑定函数的作用:主要用于把 socket 绑定到主机地址上。

网络编程--TCP/UDP 通信模型

常用实例:

// 初始化主机信息
struct sockaddr_in my_addr;
memset(&my_addr, 0, sizeof(struct sockaddr_in)); // 清空主机地址
// bzero(&my_addr, sizeof(struct sockaddr_in));
my_addr.sin_family = AF_INET; // 定义协议族:IPV4
my_addr.sin_port = htons(8888); // 定义端口号:把主机字节序转化为网络字节序
my_addr.sin_addr.s_addr = inet_addr("192.168.0.101") ; // 将ip 点分十进制转化为二进制,并转化为网络字节序
// 把 socket 绑定到主机地址上 
if(bind(sfd, (struct sockaddr *)&my_addr), sizeof(struct sockaddr_in) == -1) {
    perror("bind");
    close(sfd);
    exit(-1);
}

注意:

  • 如果设置:my_addr.sin_port = 0,函数会自动选择一个未占用的端口来使用;
  • 如果设置: my_addr.sin_addr.s_addr = INADDR_ANY,系统会自动填入本机 IP 地址;

监听 listen()


listen 函数:主要作用是用于监听端口,检测是否有连接请求信号。

网络编程--TCP/UDP 通信模型

常用实例:

// 监听 sfd,设置最大的连接数为 10
if(listen(sfd, 10) == -1) {
    perror("listen");
    close(sfd);
    exit(-1);
}

接受请求 accept()


accept 函数用于接受远程客户端的连接请求,建立与客户机之间的通信连接。假如没有客户端发出请求,服务器默认将在此处阻塞。

网络编程--TCP/UDP 通信模型

注意: 服务器处于监听状态时,如果某时刻获得了客户机的连接请求,此时并不是立即处理这个请求,而是将这个请求放在等待队列中,当系统有空闲时再处理客户机的连接请求。

常用实例:

struct sockaddr_in clientaddr; // 用于存储客户端主机信息
bzero(&clientaddr, sizeof(struct sockaddr)); // 情况结构 clientaddr
int addrlen = sizeof(struct sockaddr_in); // 计算结构 clientaddr 的长度
// 接收客户端的请求,并把客户端 socket 数据存入结构 clientaddr 中。
int new_fd = accept(sfd, (struct sockaddr *)&clientaddr, &addrlen); // 返回客户端 Socket
if (-1 == new_fd) {
    perror("accept");
    close(sfd);
    exit(-1);
}
print("%s %d success connect\n", inet_ntoa(clientaddr.sin_addr), ntoths(clientaddr.sin_port));

连接服务器 connect()


connect 函数:将客户端 Socket 连接至服务器。主要用在 TCP 客户端。

网络编程--TCP/UDP 通信模型

常用实例:

// 存储服务器IP、端口信息
struct sockaddr_in saddr; // 用于存储服务器socket数据
bzero(&seraddr, sizeof(struct sockaddr_in)); // 清空结构 saddr
seraddr.sin_family = AF_INET; // IPv4 网络
seraddr.sin_port = htons(8888); // 把端口设置为网络字节序
seraddr.sin_addr.s_addr = inet_addr("192.168.0.101"); // 把服务器IP设置为网络字节序的二进制

// 本地socket连接服务器的socket.
if(connect(cfd, (struct sockaddr *)&saddr, sizeof(struct sockaddr)) == -1) {
    perror("connect");
    close("sfd");
    exit(-1);
} 

发送数据 send()/sendto()


send 函数:主要用在 TCP 协议中,其作用是向指定的服务器/客户端发送数据;
sendto() 函数:主要用在 UDP 协议中,其作用是向指定的服务器/客户端发送数据;

网络编程--TCP/UDP 通信模型
网络编程--TCP/UDP 通信模型
网络编程--TCP/UDP 通信模型

常用实例:

// 在 TCP 中,服务器(客户端)向客户端(服务器)发送字符串 "hello"。
if(send(client_fd, "hello", 6, 0) == -1) {
    perror("send");
    close(client_fd);
    exit(-1);
}

// 在 UDP 中,服务器(或客户端)向客户端(或服务器)发送字符串 "hello",
// 在UDP中,需要指明对方的地址信息(socket信息)
if(sendto(socket_fd, "hello", 6, 0, (struct sockaddr *)&toaddr, sizeof(struct sockaddr) == -1) {
    perror("sendto");
    close(client_fd);
    exit(-1);
} 

接收数据 recv()/recvfrom()


recv() 函数:主要用在 TCP 中,其作用是接收来自服务器/客户端的数据;
recvfrom() 函数:主要用在 UDP 中,其作用是接收来自服务器/客户端的数据;

网络编程--TCP/UDP 通信模型
网络编程--TCP/UDP 通信模型
网络编程--TCP/UDP 通信模型

常用实例:

// 在 TCP 中,recv 通过已经建立联系的socket client_fd 进行联系
// 服务器(客户端)向客户端(服务器)发送数据
char buf[512] = {0};
if(recv(client_fd, buf, sizeof(buf), 0) == -1) {
    perror("recv");
    close(client_fd);
    exit(-1);
}
puts(buf);

// 在 UCP 中,服务器(客户端)向客户端(或服务器)发送数据;
// 需要指明对方的socket信息
char buf[512] = {0};
if(recvfrom(socket_fd, buf, sizeof(buf), 0, (struct sockaddr *)&fromaddr, sizeof(struct sockaddr)) == -1) {
    perror("recvfrom");
    close(socket_fd);
    exit(-1);
}
puts(buf);
相关标签: 网络编程