echo服务器问题

服务端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h>
#include <cerrno>
#include <vector>
#include <fcntl.h>
#include <assert.h>
#include <sys/epoll.h>
#include <thread>
#define PORT 5000
#define SERVER_IP "127.0.0.1"
#define MAX_EVENTS 5

void set_nonblocking(int sockfd){
int flags = fcntl(sockfd, F_GETFL);
flags |= O_NONBLOCK;
fcntl(sockfd, F_SETFL, flags);
}

int main(){
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
assert(listen_fd >= 1);
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(PORT);
inet_pton(AF_INET, SERVER_IP, &address.sin_addr);
int ret = bind(listen_fd, (struct sockaddr*)(&address), sizeof(address));
assert(ret != -1);
int ret1 = listen(listen_fd, 5);
assert(ret1 != -1);
set_nonblocking(listen_fd);

int epoll_fd = epoll_create1(0);
assert(epoll_fd != -1);

struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = listen_fd;

if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev) == -1){
std::cerr << "Failed to add file descriptor to epoll" << std::endl;
close(epoll_fd);
return 1;
}

struct epoll_event events[MAX_EVENTS];

while(true){
int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
for(int i = 0; i < nfds; ++i){
if(events[i].data.fd == listen_fd){
struct sockaddr_in client;
socklen_t client_len = sizeof(client);
int sock_fd = accept(listen_fd, (struct sockaddr*)(&client), &client_len);
set_nonblocking(sock_fd);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = sock_fd;
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock_fd, &ev) == -1){
std::cerr << "Failed to add client socket file descriptor to epoll" << std::endl;
}
}
else{
int client_fd = events[i].data.fd;
char buf[1024] = {0};
int recv_size;

while((recv_size = recv(client_fd, buf, sizeof(buf), 0)) > 0){
std::cout << "服务端接收到的消息为:" << buf << std::endl;
send(client_fd, buf, sizeof(buf), 0);
}

if(recv_size == 0 || (recv_size == -1 && errno != EAGAIN && errno != EWOULDBLOCK)){
if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, &ev) == -1){
std::cerr << "Failed delete the client_fd" << std::endl;
}
close(client_fd);
}
}
}
}
close(listen_fd);
close(epoll_fd);
return 0;
}

客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h>
#include <cerrno>
#include <vector>
#include <fcntl.h>
#include <assert.h>
#include <sys/epoll.h>
#include <thread>
#include <mutex>
#define PORT 5000
#define SERVER_IP "127.0.0.1"
#define MAX_EVENTS 5
std::mutex mtx;

int i = 0;

void client_thread_function(){
int client_sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr);
if(connect(client_sockfd, (struct sockaddr*)(&serv_addr), sizeof(serv_addr))){
std::cerr << "Connection failed!" << std::endl;
close(client_sockfd);
return;
}
char buf[1024] = {0};
memset(buf, 0, sizeof(buf));
strcpy(buf, "Hello, world!");
int send_size = send(client_sockfd, buf, strlen(buf), 0);
if(send_size < 0) std::cerr << "Error sending data: " << strerror(errno) << std::endl;
int recv_size = recv(client_sockfd, buf, send_size, 0);
if(recv_size < 0) {
std::cerr << "Error recving data: " << strerror(errno) << std::endl;
} else {
std::unique_lock<std::mutex> lock(mtx);
i += 1;
std::cout << "客户端" << i << "接收信息为:" << buf << std::endl;
}
close(client_sockfd);
}

int main(){
const int thread_num = 5;
std::vector<std::thread> client_threads;
for(int i = 0; i < thread_num; ++i){
client_threads.push_back(std::thread(client_thread_function));
}

for(auto& t : client_threads){
t.join();
}

return 0;
}


运行时问题及结果截图

在服务端与客户端均运行起来时,会发现程序并不能完整运行完,可能运行三条/一条/直接卡住,一条没有等情况,截图如下:

0条echo,直接卡住不动

如上图所示,就显示一条echo回声消息,服务端跟客户端就都卡在这不动了。

0条echo,直接卡住不动

解决方案(我并不清楚怎么就解决了!)

将ET边缘触发模式改为LT水平触发模式就OK了,但从ET结果来看,程序貌似阻塞住了,但哪里会产生阻塞呢?十分不理解?还是其他问题呢(并非阻塞)?