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(¶ms);
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(¶ms);
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,但也许我的技能是民意调查,客户无法与服务器通信,所以我不知道该怎么做
结构缺陷
,但是您的使用无效,只是为了进行阻止读数,而不是学习如何编写适当的
broadcast
/select
/poll
循环。 构造解决方案
如果您将插座进行非障碍物,则可以将其写入单个线程。对于此工作,您需要动态数量的缓冲区,并且当非障碍发送无法一次发送整个东西时,您需要管理部分消耗的缓冲区。
由于每个缓冲区将被发送到多个插座,并且它们可能会以不同的速率排出,您还需要参考计数器来跟踪给定的缓冲区何时最终完成,并且可以重复使用。最终,您需要使用
epoll
(或其他)在客户插座变得可读时告诉您两者,当带有未完成的发送缓冲区的套接字的插座变得可撰写时。
epoll
,但这本身就是一个整体。 我希望看到某人至少会在高分辨率的时间戳中添加基本记录,如果他们试图大致了解程序的时间,但是
perf
会更准确,更灵活且更少侵入性。