LINUX 入门 8

LINUX 入门 8

day10 20240507 耗时:90min 有点到倦怠期了

课程链接地址

第8章 TCP服务器

1 TCP服务器的介绍

开始讲服务器端,之前是客户端DNS+https请求

  1. 基础:网络编程
  2. 并发服务器:多客户端
    1. 一请求,一线程 veryold
    2. IO多路复用,epoll/select上一章讲过了
  3. TCP server百万级连接

借助netassist.exe

2 TCP并发网络网络编程 一请求一线程

tcp server类似酒店迎宾领过去,监听listen

server有对应客户端的连接有socket 连接类似服务员点菜

没懂好多用法

  1. void *client_routine(void *arg){
        int clientfd = *(int *) arg;
    } 
    

    这是一个使用多线程处理客户端请求的例子。在这个例子中,每个客户端连接都会创建一个新的线程,并且通过 client_routine 函数进行处理。

    下面是对提供的代码片段的解释:

    • void *client_routine(void *arg) 是一个线程函数,用于处理单个客户端连接。
    • int clientfd = *(int *) arg; 将传入参数 arg 解引用为整数类型,并将其赋值给 clientfd 变量。假设传入参数是一个指向整数类型的指针,即客户端套接字描述符。 *(int *) arg;它首先将 arg 强制转换为指向整数的指针,然后使用解引用操作符 * 获取该指针所指向的值。

    你可以在该函数中编写适当的代码来处理客户端请求,例如读取和发送数据等操作。请注意,在每个线程内部需要负责释放相关资源并确保线程安全性。

步骤:

gcc -o tcp_server tcp_server.c -lpthread
./tcp_server 8888

服务器就起来了

打开netassist 改远程地址: 192.168.243.128:8888

在这里插入图片描述

有bug连上了,但是点发送以后收不到!!!

或者是bind error, 没调出来,可能那里打错了,老师的是可以的

  1. 起多个客户端send,如何取区分

    sockfd无法解决,需要应用协议发的内容不同<fromid: xxxx>

  2. 缺点:不适合超多client,内存不够; 用epoll改

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <pthread.h>

#include <errno.h>
#include <fcntl.h>

#include <sys/epoll.h>
#include <unistd.h> //close要


#define BUFFER_LENGTH 1024

// 法一 一请求一线程
void *client_routine(void *arg){
    int clientfd = *(int *) arg;
    while(1){
        char buffer[BUFFER_LENGTH] = {0}; 
        // 用于从客户端套接字中接收数据并将其存储到缓冲区中。clientfd:表示要接收数据的套接字文件描述符。buffer:表示接收数据的缓冲区,也就是存放接收到的数据的位置。BUFFER_LENGTH:表示期望接收的最大字节数,即缓冲区的大小。0:表示额外选项,通常设置为 0。
        int len = recv(clientfd, buffer, BUFFER_LENGTH, 0);
        if(len < 0){
            // 没数据,如果阻塞,就是一直等,返回-1
            // 在非阻塞 I/O 模式下,当没有可用数据时,recv() 函数可能返回 -1 并设置 errno 为 EAGAIN 或 EWOULDBLOCK。这表示当前没有数据可供接收,并且稍后可能会有更多数据可用。因此,这段代码的作用是检测 errno 是否等于 EAGAIN 或 EWOULDBLOCK,以判断是否需要继续等待更多数据的到达。
            if(errno == EAGAIN ||errno == EWOULDBLOCK){
                close(clientfd);
                break;
            }else if(len == 0){ //disconnect
                close(clientfd);
                break;
            }else{
                printf("recv: %s, %d byte(s)\n",buffer, len);
            }
        }
    }
} 

// 1 socket创建
int main(int argc, char*argv[]){
    if(argc<2) {
        printf("param error\n");
        return -1;
    }

    int port = atoi(argv[1]);

    int sockfd = socket(AF_INET, SOCK_STREAM, 0); //聘请一个迎宾的listen

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(struct sockaddr_in));
    addr.sin_family  = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY; //任意地址不确定

    // 0成功 1失败
    // 函数bind()将套接字与特定的IP地址和端口号进行绑定,以便后续接收来自该地址的连接请求。
    // 而listen()则表示开始监听连接请求,并指定最大允许等待连接队列的长度为5。这意味着服务器可以同时处理5个未处理的连接请求,超过这个数量的请求将被拒绝或排队等待处理。
    if(bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0){
        perror("bind error");
        return -2;
    }
    if(listen(sockfd, 5) < 0){
        perror("listen error");
        return -3;
    } 

    // 2迎宾sockfd 一直等着 为客户client介绍服务员socket
    while(1){
        struct sockaddr_in client_addr;
        memset(&client_addr, 0, sizeof(struct sockaddr_in));
        
        socklen_t client_len = sizeof(client_addr);
        
        // 使用accept函数接受来自服务器监听套接字 sockfd 的客户端连接请求,并将客户端的地址信息存储在名为 client_addr 的结构体中。
        int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len); 

        // 法一 一请求一线程
        // 请求来了创建线程
        pthread_t thread_id;
        pthread_create(&thread_id, NULL, client_routine, &clientfd);
    }



}

3 TCP并发网络编程io多路复用epoll 水平触发与边沿触发

没敲,就看了一下

  1. what is epoll

    超多clients 对server发request

    检测到哪个client发了数据

    1. epoll_create
    2. epoll_ctl control管理 增删改
    3. epoll_wait() 多长时间去一次
#if 0

	while (1) {

		struct sockaddr_in client_addr;
		memset(&client_addr, 0, sizeof(struct sockaddr_in));
		socklen_t client_len = sizeof(client_addr);

		int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
		
		pthread_t thread_id;
		pthread_create(&thread_id, NULL, client_routine, &clientfd);

	}
	
#else

	int epfd = epoll_create(1);  
	struct epoll_event events[EPOLL_SIZE] = {0};

	struct epoll_event ev;
	ev.events = EPOLLIN; 
	ev.data.fd = sockfd;
	epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);

	
	while (1) {

		int nready = epoll_wait(epfd, events, EPOLL_SIZE, 5); // -1, 0, 5
		if (nready == -1) continue;

		int i = 0;
		for (i = 0;i < nready;i ++) {

			if (events[i].data.fd == sockfd) { // listen 

				struct sockaddr_in client_addr;
				memset(&client_addr, 0, sizeof(struct sockaddr_in));
				socklen_t client_len = sizeof(client_addr);

				int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);

				ev.events = EPOLLIN | EPOLLET; 
				ev.data.fd = clientfd;
				epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev);

			} else {

				int clientfd = events[i].data.fd;
				
				char buffer[BUFFER_LENGTH] = {0};
				int len = recv(clientfd, buffer, BUFFER_LENGTH, 0);
				if (len < 0) {
					close(clientfd);

					ev.events = EPOLLIN; 
					ev.data.fd = clientfd;
					epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev);
					
				} else if (len == 0) { // disconnect
					close(clientfd);

					ev.events = EPOLLIN; 
					ev.data.fd = clientfd;
					epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev);
					
				} else {
					printf("Recv: %s, %d byte(s)\n", buffer, len);
				}
				
				
			}

		}

	}
	

#endif
	

一边听,敲,记笔记云里雾里的

  1. 关于io有无数据?如何检测 epoll_wait
    1. 有1 无0
    2. 一种是水平触发EPOLLIN:有没有;一种是边沿触发EPOLLET:检测从无变有

**面试重点:**epoll两种触发,reactor,协程,epoll 在sockfd set集合里

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-05-12 23:06:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-05-12 23:06:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-05-12 23:06:02       82 阅读
  4. Python语言-面向对象

    2024-05-12 23:06:02       91 阅读

热门阅读

  1. 什么股指期货滚IC的意思?

    2024-05-12 23:06:02       32 阅读
  2. PostgreSQL自带的命令行工具14- pg_test_timing

    2024-05-12 23:06:02       26 阅读
  3. socket编程 学习笔记 理解

    2024-05-12 23:06:02       33 阅读
  4. Android RadioButton,定制按钮样式

    2024-05-12 23:06:02       33 阅读
  5. Vue router(路由守卫)

    2024-05-12 23:06:02       29 阅读
  6. 大话C语言:第11篇 运算符之自增减运算符

    2024-05-12 23:06:02       31 阅读
  7. video.js的请求头问题

    2024-05-12 23:06:02       26 阅读
  8. 算法学习笔记(Nim游戏)

    2024-05-12 23:06:02       34 阅读
  9. 蓝桥杯备战12.阶乘

    2024-05-12 23:06:02       39 阅读
  10. 基于单片机的宠物智能投喂系统研究

    2024-05-12 23:06:02       31 阅读