Skip to content

Commit a654ffd

Browse files
committed
socket;
1 parent 8be610e commit a654ffd

10 files changed

+751
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
*.app
3333

3434
# Specific files
35+
.cache
3536
.vscode
3637
build
3738
bin-*

CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,8 @@ add_subdirectory(Breakpad)
9090
add_subdirectory(DesignPattern)
9191
add_subdirectory(Glog)
9292
add_subdirectory(Mutex)
93+
94+
if(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux")
95+
add_subdirectory(Client)
96+
add_subdirectory(Server)
97+
endif()

Client/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
add_executable(Client client.cpp)
2+
target_link_libraries(Client pthread)

Client/client.cpp

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#include <arpa/inet.h> //inet_ntoa
2+
#include <fcntl.h>
3+
#include <iostream>
4+
#include <netinet/in.h> //sockaddr_in
5+
#include <pthread.h>
6+
#include <stdio.h> //perror
7+
#include <stdlib.h> //exit()
8+
#include <string.h>
9+
#include <sys/socket.h> //socket()
10+
#include <unistd.h>
11+
12+
using namespace std;
13+
14+
#define ip "0.0.0.0"
15+
#define port 8888
16+
#define maxsize 1024
17+
#define quit "quit" //关闭命令
18+
19+
static int sockfd;
20+
21+
//配置非阻塞模式
22+
void setNonBlocking(int fd)
23+
{
24+
int flag = fcntl(fd, F_GETFL, 0);
25+
if (flag < 0) {
26+
perror("fcntl F_GETFL fail");
27+
return;
28+
}
29+
flag |= O_NONBLOCK;
30+
if (fcntl(fd, F_SETFL, flag) < 0) {
31+
perror("fcntl F_SETFL fail");
32+
}
33+
}
34+
35+
int connectToServer()
36+
{
37+
struct sockaddr_in clIentaAddr;
38+
39+
while (1) {
40+
if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
41+
perror("sockfd failed!");
42+
continue;
43+
}
44+
45+
//设置服务器的地址
46+
clIentaAddr.sin_family = AF_INET;
47+
clIentaAddr.sin_port = htons(port);
48+
//inet_pton(AF_INET, ip, &clientsock.sin_addr.s_addr);
49+
clIentaAddr.sin_addr.s_addr = inet_addr(ip);
50+
51+
cout << inet_ntoa(clIentaAddr.sin_addr) << ":" << clIentaAddr.sin_port << endl;
52+
53+
if ((connect(sockfd, reinterpret_cast<struct sockaddr *>(&clIentaAddr), sizeof(clIentaAddr)))
54+
== -1) {
55+
perror("connect failed!");
56+
close(sockfd);
57+
sleep(1);
58+
continue;
59+
} else
60+
break;
61+
}
62+
cout << "服务器连接成功:" << sockfd << endl;
63+
setNonBlocking(sockfd);
64+
return sockfd;
65+
}
66+
67+
void *readdata(void *)
68+
{
69+
char readbuf[maxsize];
70+
fd_set fds;
71+
struct timeval tv;
72+
73+
tv.tv_sec = 30; //5s超时设置
74+
tv.tv_usec = 0;
75+
76+
while (1) {
77+
FD_ZERO(&fds); //每次循环都要清空集合,否则不能检测描述符变化
78+
FD_SET(sockfd, &fds); //添加描述符
79+
ssize_t ret = select(sockfd + 1, &fds, nullptr, nullptr, &tv);
80+
//cout<<"z="<<z<<endl;
81+
if (ret == -1) {
82+
//perror("select error:");
83+
break;
84+
} else if (FD_ISSET(sockfd, &fds)) {
85+
memset(readbuf, 0, sizeof(readbuf));
86+
ssize_t nread = recv(sockfd, readbuf, sizeof(readbuf), 0);
87+
//cout<<"read"<<nread<<endl;
88+
if (nread == 0) {
89+
if (sockfd) {
90+
cout << "服务端关闭\n关闭客户端" << endl;
91+
close(sockfd);
92+
}
93+
exit(1);
94+
}
95+
if (nread < 0) {
96+
if (sockfd) {
97+
close(sockfd);
98+
}
99+
exit(-1);
100+
//sockfd=connecttoserver(); //重连
101+
} else if (nread > 0) {
102+
cout << "服务端:" << readbuf << endl;
103+
}
104+
}
105+
}
106+
//cout<<"close accept:"<<sockfd<<endl;
107+
//cout<<"close read"<<endl;
108+
//close(sockfd);
109+
return nullptr;
110+
}
111+
112+
void *senddata(void *)
113+
{
114+
fd_set fds;
115+
char buf[maxsize];
116+
ssize_t nsend = 0;
117+
nsend = send(sockfd, "hello server", strlen("hello server"), 0);
118+
if (nsend <= 0) {
119+
exit(1);
120+
}
121+
while (1) {
122+
FD_ZERO(&fds); //每次循环都要清空集合,否则不能检测描述符变化
123+
FD_SET(STDIN_FILENO, &fds);
124+
if (FD_ISSET(STDIN_FILENO, &fds)) {
125+
memset(buf, 0, sizeof(buf));
126+
if (fgets(buf, maxsize, stdin) == nullptr) {
127+
printf("End...\n");
128+
exit(EXIT_FAILURE);
129+
} else {
130+
buf[strlen(buf) - 1] = '\0'; //减一的原因是不要回车字符
131+
//经验值:这一步非常重要的哦!!!!!!!!
132+
if (strcmp(buf, quit) == 0) {
133+
cout << "Quit command!" << endl;
134+
break; //关闭客户端
135+
//exit(1);//关闭服务端
136+
}
137+
send(sockfd, buf, strlen(buf), 0);
138+
}
139+
}
140+
}
141+
cout << "客户端关闭" << endl;
142+
if (sockfd) {
143+
close(sockfd);
144+
}
145+
return nullptr;
146+
}
147+
148+
int main()
149+
{
150+
connectToServer();
151+
152+
pthread_t t1, t2;
153+
if (pthread_create(&t1, nullptr, readdata, nullptr)) {
154+
perror("readthread error:");
155+
return -1;
156+
}
157+
if (pthread_create(&t2, nullptr, senddata, nullptr)) {
158+
perror("sendthread error:");
159+
return -1;
160+
}
161+
if (pthread_join(t1, nullptr) == -1) {
162+
perror("readjoin error");
163+
return -1;
164+
}
165+
if (pthread_join(t2, nullptr) == -1) {
166+
perror("sendjoin error");
167+
return -1;
168+
}
169+
170+
close(sockfd);
171+
return 0;
172+
}

Server/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
add_executable(server_select server_select.cc socket.hpp socket.cc)
2+
add_executable(server_poll server_poll.cc socket.hpp socket.cc)
3+
add_executable(server_epoll server_epoll.cc socket.hpp socket.cc)

Server/server_epoll.cc

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
#include <Server/socket.hpp>
2+
3+
#include <cstdio>
4+
#include <cstring>
5+
#include <iostream>
6+
#include <list>
7+
#include <sys/epoll.h>
8+
#include <sys/socket.h>
9+
#include <unistd.h>
10+
11+
#define MAXCN 10 //连接队列中的个数
12+
#define quit "quit" //关闭命令
13+
14+
void server_epoll(int serverfd)
15+
{
16+
std::list<int> clientfds;
17+
struct epoll_event event;
18+
//事件数组
19+
struct epoll_event eventList[MAXCN];
20+
int epollfd = epoll_create(MAXCN); //
21+
int timeout = 3000;
22+
event.events = EPOLLIN | EPOLLET;
23+
event.data.fd = serverfd;
24+
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, serverfd, &event) < 0) {
25+
perror("Epoll Add serverfd Fail:");
26+
return;
27+
}
28+
setNonBlocking(serverfd); //配置非阻塞模式
29+
event.data.fd = STDIN_FILENO;
30+
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &event) < 0) {
31+
perror("Epoll Add STDIN_FILENO Fail:");
32+
return;
33+
}
34+
setNonBlocking(STDIN_FILENO);
35+
//epoll
36+
while (1) {
37+
std::cout << "等待客户端连接..." << std::endl;
38+
//epoll_wait
39+
int ret = epoll_wait(epollfd, eventList, MAXCN, timeout);
40+
if (ret < 0) {
41+
perror("epoll error:");
42+
break;
43+
} else if (ret == 0) {
44+
printf("timeout ...\n");
45+
continue;
46+
}
47+
//直接获取了事件数量,给出了活动的流,这里是和poll区别的关键
48+
int i = 0;
49+
for (i = 0; i < ret; i++) {
50+
//错误退出
51+
if ((eventList[i].events & EPOLLERR) || (eventList[i].events & EPOLLHUP)
52+
|| !(eventList[i].events & EPOLLIN)) {
53+
perror("epoll error:");
54+
close(eventList[i].data.fd);
55+
continue;
56+
}
57+
if (eventList[i].data.fd == STDIN_FILENO) {
58+
char buf[BUFSIZ];
59+
memset(buf, 0, sizeof buf);
60+
if (fgets(buf, BUFSIZ, stdin) == nullptr) {
61+
perror("End:");
62+
exit(EXIT_FAILURE);
63+
} else {
64+
buf[strlen(buf) - 1] = '\0'; //减一的原因是不要回车字符
65+
// 经验值:这一步非常重要的哦!!!!!!!!
66+
if (strcmp(buf, quit) == 0) {
67+
printf("Quit command!\n");
68+
for (int j : clientfds) {
69+
send(j, buf, strlen(buf), 0);
70+
close(j);
71+
}
72+
close(serverfd);
73+
printf("关闭服务端\n");
74+
clientfds.clear();
75+
break; //关闭服务端
76+
}
77+
for (int j : clientfds) {
78+
ssize_t nsend = send(j, buf, strlen(buf), 0);
79+
if (nsend < 0) {
80+
perror("send");
81+
}
82+
printf("clinet[%d]\n", j);
83+
}
84+
}
85+
} else if (eventList[i].data.fd == serverfd) {
86+
int clientfd = server_accept(serverfd);
87+
if (clientfd <= 0) {
88+
perror("accept error:");
89+
continue;
90+
}
91+
show_info(clientfd);
92+
if (clientfds.size() >= (MAXCN - 2)) {
93+
fprintf(stderr, "connfd size over %d\n", MAXCN);
94+
close(clientfd);
95+
} else {
96+
//将新建立的连接添加到EPOLL的监听中
97+
struct epoll_event event_;
98+
event_.data.fd = clientfd;
99+
event_.events = EPOLLIN | EPOLLET;
100+
epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &event_);
101+
setNonBlocking(clientfd); //配置非阻塞模式
102+
clientfds.push_back(clientfd); //
103+
}
104+
} else {
105+
char buf[BUFSIZ];
106+
memset(buf, 0, sizeof buf);
107+
int sockfd = eventList[i].data.fd;
108+
//接受客户端数据
109+
ssize_t nread = recv(sockfd, buf, sizeof buf, 0);
110+
show_info(sockfd);
111+
if (nread <= 0) {
112+
int res = epoll_ctl(epollfd,
113+
EPOLL_CTL_DEL,
114+
sockfd,
115+
nullptr); //将该文件描述符从红黑树摘除
116+
if (res == -1) {
117+
perror("epoll_ctl error");
118+
}
119+
close(sockfd); //关闭与该客户端的链接
120+
printf("客户端连接关闭\n");
121+
clientfds.remove(sockfd);
122+
} else { //正常接收到服务器的数据
123+
printf("client[%d] send:%s\n", i, buf);
124+
snprintf(buf, 1024, "%s", "hello client!");
125+
send(eventList[i].data.fd, buf, 1024, 0);
126+
}
127+
}
128+
}
129+
}
130+
if (serverfd) {
131+
close(serverfd);
132+
}
133+
if (epollfd) {
134+
close(epollfd);
135+
}
136+
}
137+
138+
int main()
139+
{
140+
std::cout << "Hello World!" << std::endl;
141+
int serverfd = socketListenBind();
142+
if (serverfd < 0) {
143+
perror("Failed to open server:");
144+
return -1;
145+
}
146+
printf("serverfd=%d\n", serverfd);
147+
server_epoll(serverfd);
148+
return 0;
149+
}

0 commit comments

Comments
 (0)