在第三端客户加入时(C ++ ALSA/TCP实现)

问题描述 投票:0回答:1
哪些建筑缺陷或实施细节可能会导致这种渐进式延迟在多客户场景中特别增加?我应该如何介绍和优化此系统?

Server.cpp

#include <iostream> #include <vector> #include <thread> #include <mutex> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <algorithm> #define PORT 8888 #define BUFFER_SIZE 4096 std::vector<int> clients; std::mutex mtx; void broadcast(int sender, const char* buffer, ssize_t len) { std::lock_guard<std::mutex> lock(mtx); for(int client : clients) { if(client != sender) { send(client, buffer, len, 0); } } } void handle_client(int sock) { char buffer[BUFFER_SIZE]; while(true) { ssize_t len = recv(sock, buffer, BUFFER_SIZE, 0); if(len <= 0) break; broadcast(sock, buffer, len); } close(sock); mtx.lock(); clients.erase(std::remove(clients.begin(), clients.end(), sock), clients.end()); mtx.unlock(); } int main() { int server_fd = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in address{AF_INET, htons(PORT), INADDR_ANY}; setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, nullptr, 0); bind(server_fd, (sockaddr*)&address, sizeof(address)); listen(server_fd, 5); while(true) { sockaddr_in client_addr; socklen_t addr_len = sizeof(client_addr); int client_sock = accept(server_fd, (sockaddr*)&client_addr, &addr_len); std::lock_guard<std::mutex> lock(mtx); clients.push_back(client_sock); std::thread(handle_client, client_sock).detach(); } return 0; }

client.cpp
#include <iostream>
#include <thread>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <alsa/asoundlib.h>

#define SERVER_IP "127.0.0.1"
#define PORT 8888
#define SAMPLE_RATE 44100
#define CHANNELS 1
#define BUFFER_FRAMES 512
#define FORMAT SND_PCM_FORMAT_S16_LE

int sock;
bool running = true;
snd_pcm_t *capture_handle;
snd_pcm_t *playback_handle;

snd_pcm_t* InitializeCaptureDevice() {
    snd_pcm_t *handle;
    snd_pcm_hw_params_t *params;
    
    int err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);
    if (err < 0) {
        std::cerr << "Capture open error: " << snd_strerror(err) << std::endl;
        return nullptr;
    }

    snd_pcm_hw_params_malloc(&params);
    snd_pcm_hw_params_any(handle, params);
    
    snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(handle, params, FORMAT);
    snd_pcm_hw_params_set_channels(handle, params, CHANNELS);
    unsigned int rate = SAMPLE_RATE;
    snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0);
    
    if ((err = snd_pcm_hw_params(handle, params)) < 0) {
        std::cerr << "Capture params error: " << snd_strerror(err) << std::endl;
        snd_pcm_close(handle);
        return nullptr;
    }

    snd_pcm_hw_params_free(params);
    return handle;
}

snd_pcm_t* InitializePlaybackDevice() {
    snd_pcm_t *handle;
    snd_pcm_hw_params_t *params;
    
    int err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
    if (err < 0) {
        std::cerr << "Playback open error: " << snd_strerror(err) << std::endl;
        return nullptr;
    }

    snd_pcm_hw_params_malloc(&params);
    snd_pcm_hw_params_any(handle, params);
    
    snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(handle, params, FORMAT);
    snd_pcm_hw_params_set_channels(handle, params, CHANNELS);
    unsigned int rate = SAMPLE_RATE;
    snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0);
    
    if ((err = snd_pcm_hw_params(handle, params)) < 0) {
        std::cerr << "Playback params error: " << snd_strerror(err) << std::endl;
        snd_pcm_close(handle);
        return nullptr;
    }

    snd_pcm_hw_params_free(params);
    return handle;
}

void audio_in_thread() {
    short buffer[BUFFER_FRAMES];
    while(running) {
        snd_pcm_readi(capture_handle, buffer, BUFFER_FRAMES);
        send(sock, buffer, BUFFER_FRAMES*sizeof(short), 0);
    }
}

void audio_out_thread() {
    short buffer[BUFFER_FRAMES];
    while(running) {
        ssize_t len = recv(sock, buffer, BUFFER_FRAMES*sizeof(short), 0);
        if(len > 0) {
            snd_pcm_writei(playback_handle, buffer, len/sizeof(short));
        }
    }
}

int main() {
    sock = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in server_addr{AF_INET, htons(PORT)};
    inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);
    connect(sock, (sockaddr*)&server_addr, sizeof(server_addr));

    if(!(capture_handle = InitializeCaptureDevice()) || 
       !(playback_handle = InitializePlaybackDevice())) {
        std::cerr << "Audio device init failed" << std::endl;
        return -1;
    }

    std::thread(audio_in_thread).detach();
    std::thread(audio_out_thread).detach();

    std::cout << "Press 'q' to quit..." << std::endl;
    while(getchar() != 'q');
    
    running = false;
    close(sock);
    snd_pcm_close(capture_handle);
    snd_pcm_close(playback_handle);
    return 0;
}

我尝试使用epoll,但也许我的技能是民意调查,客户无法与服务器通信,所以我不知道该怎么做
    

结构缺陷
c++ network-programming audio alsa
1个回答
0
投票
slow

您有threads

,但是您的使用无效,只是为了进行阻止读数,而不是学习如何编写适当的

broadcast
/select/

poll

循环。 构造解决方案

如果您将插座进行非障碍物,则可以将其写入单个线程。
对于此工作,您需要动态数量的缓冲区,并且当非障碍发送无法一次发送整个东西时,您需要管理部分消耗的缓冲区。
由于每个缓冲区将被发送到多个插座,并且它们可能会以不同的速率排出,您还需要参考计数器来跟踪给定的缓冲区何时最终完成,并且可以重复使用。
最终,您需要使用
epoll
(或其他)在客户插座变得可读时告诉您两者,当带有未完成的发送缓冲区的套接字的插座变得可撰写时。

最终,分析。您应该考虑学习使用

epoll

,但这本身就是一个整体。 我希望看到某人至少会在高分辨率的时间戳中添加基本记录,如果他们试图大致了解程序的时间,但是

perf

会更准确,更灵活且更少侵入性。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.