三:基于TCP的服务端/客户端

1 理解TCP和UDP

  • 其中四层模型说的就是TCP(UDP)/IP协议栈
并列图片
Image 1 Image 2

2 补充函数解释

Image
  • listen详解
#include <sys/socket.h>

/**
* @param[1]: 希望进入等待状态的套接字
* @param[2]: 连接请求等待队列的长度
*/
int listen(int sock, int backlog);

当客户端发送连接请求时,并不一定能立即连接到。尽管此时服务端处于等待连接请求状态(listen),但是由于系统正忙,此连接请求需要进入连接请求等待队列,listen第二个参数便是设置此等待队列的大小。

  • accept函数详解
#include <sys/socket.h>

/**
* @brief : 受理连接请求等待队列中待处理的连接请求。
* @param[1] : sock:服务器套接字的文件描述符;
* @param[2] : addr:用于保存发起连接请求的客户端地址信息;
* @param[3] : addrlen:第二个参数的长度。
*/
int accept(int sockfd, struct sockaddr *addr, socklen_t addrlen);                                  
  • accept 函数会受理连接请求等待队列中待处理的客户端连接请求,它从等待队列中取出 1 个连接请求,创建套接字并完成连接请求。如果等待队列为空,accpet 函数会阻塞,直到队列中出现新的连接请求才会返回。
  • 它会在内部产生一个新的套接字并返回其文件描述符,该套接字用于与客户端建立连接并进行数据 I/O。新的套接字是在 accept 函数内部自动创建的,并自动与发起连接请求的客户端建立连接。
    accept 执行完毕后会将它所受理的连接请求对应的客户端地址信息存储到第二个参数 addr 中。
  • connect() 函数详解
#include <sys/socket.h>

/**
* @brief : 请求连接。
* @param[2] : 保存目标服务器端地址信息的结构体指针
*/
int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen);  

客户端调用 connect 函数后会阻塞,直到发生以下情况之一才会返回:

  1. 服务器端接收连接请求。
  2. 发生断网等异常情况而中断连接请求。

注意:上面说的”接收连接请求“并不是服务器端调用了 accept 函数,而是服务器端把连接请求信息记录到等待队列。因此 connect 函数返回后并不立即进行数据交换。

3 实现迭代回声服务端和客户端(问题版)

迭代回声服务器端与回声客户端的基本运行方式:

  1. 服务器端同一时刻只与一个客户端相连接,并提供回声服务。
  2. 服务器端依次向 5 个客户端提供服务,然后退出。
  3. 客户端接收用户输入的字符串并发送到服务器端。
  4. 服务器端将接收到的字符串数据传回客户端,即”回声“。
  5. 服务器端与客户端之间的字符串回声一直执行到客户端输入 Q 为止。
    在这里插入图片描述
    在这里插入图片描述

服务端代码

注:由于不同公司代码规范的规定不同,所以书写方式可能跟书本有出入,不过不影响内容一致

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

const int kBufferSize = 1024;

void ErrorHandling(char* message) {
   
   
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char* argv[]) {
   
   
    int server_sock;
    int client_sock;
    char message[kBufferSize];
    int str_len = 0;
    
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    socklen_t client_addr_size;

    if (argc != 2) {
   
   
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }

    server_sock = socket(PF_INET, SOCK_STREAM, 0);
    if (server_sock == -1) {
   
   
        ErrorHandling("socket() error");
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(atoi(argv[1]));

    if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
   
   
        ErrorHandling("bind() error");
    }

    if (listen(server_sock, 5) == -1) {
   
   
        ErrorHandling("listen() error");
    }

    client_addr_size = sizeof(client_addr);

    //循环变量i C11可以写里面了
    for (int i = 0; i < 5; i++) {
   
   
        client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_addr_size);
        if (client_sock == -1) {
   
   
            ErrorHandling("accept() error");
        } else {
   
   
            printf(
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值