Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
P
Performance von Anwendungen
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Saif Eddine Askri
Performance von Anwendungen
Commits
7b1bd202
Commit
7b1bd202
authored
2 months ago
by
Saif Eddine Askri
Browse files
Options
Downloads
Patches
Plain Diff
added request handling
parent
7a3b14f9
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
prak3/src/CMakeLists.txt
+2
-2
2 additions, 2 deletions
prak3/src/CMakeLists.txt
prak3/src/client.cpp
+3
-3
3 additions, 3 deletions
prak3/src/client.cpp
prak3/src/server.cpp
+118
-124
118 additions, 124 deletions
prak3/src/server.cpp
prak3/src/test.cpp
+80
-0
80 additions, 0 deletions
prak3/src/test.cpp
with
203 additions
and
129 deletions
prak3/src/CMakeLists.txt
+
2
−
2
View file @
7b1bd202
add_executable
(
client client.cpp
)
add_executable
(
my
client client.cpp
)
add_executable
(
server server.cpp
)
add_executable
(
my
server server.cpp
)
add_executable
(
test test.cpp
)
add_executable
(
test test.cpp
)
\ No newline at end of file
This diff is collapsed.
Click to expand it.
prak3/src/client.cpp
+
3
−
3
View file @
7b1bd202
...
@@ -4,7 +4,9 @@
...
@@ -4,7 +4,9 @@
#include
<arpa/inet.h>
#include
<arpa/inet.h>
#define SERVER_IP "141.100.42.11"
//#define SERVER_IP "141.100.42.11"
#define SERVER_IP "127.0.0.1"
#define PORT 2525
#define PORT 2525
#define BUFFER_SIZE 1024
#define BUFFER_SIZE 1024
...
@@ -79,6 +81,4 @@ int main(int argc, char* argv[]) {
...
@@ -79,6 +81,4 @@ int main(int argc, char* argv[]) {
// Socket schließen
// Socket schließen
close
(
sock
);
close
(
sock
);
return
0
;
return
0
;
}
}
This diff is collapsed.
Click to expand it.
prak3/src/server.cpp
+
118
−
124
View file @
7b1bd202
#include
<iostream>
#include
<iostream>
#include
<unordered_map>
#include
<vector>
#include
<thread>
#include
<thread>
#include
<mutex>
#include
<vector>
#include
<condition_variable>
#include
<queue>
#include
<cstring>
#include
<cstring>
#include
<unistd.h>
#include
<unistd.h>
#include
<arpa/inet.h>
#include
<arpa/inet.h>
#include
<
sys/epoll.h
>
#include
<
mutex
>
#define PORT 2525
#define PORT 2525
#define MAX_EVENTS 10
#define BUFFER_SIZE 1024
#define BUFFER_SIZE 1024
#define THREAD_POOL_SIZE 4
#define STORE_OPERATION 's'
#define GET_OPERATION 'g'
#define DELETE_OPERATION 'd'
std
::
unordered_map
<
std
::
string
,
std
::
string
>
store
;
struct
Request
{
std
::
mutex
store_mutex
;
char
operation
;
std
::
string
key
;
std
::
string
value
;
};
// Task-Queue für Thread-Pool
std
::
mutex
mtx
;
std
::
queue
<
int
>
task_queue
;
std
::
vector
<
Request
*>
DB
;
std
::
mutex
queue_mutex
;
std
::
condition_variable
cv
;
// Worker-Funktion für Thread-Pool
void
worker_thread
()
{
while
(
true
)
{
int
client_socket
;
{
std
::
unique_lock
<
std
::
mutex
>
lock
(
queue_mutex
);
cv
.
wait
(
lock
,
[]
{
return
!
task_queue
.
empty
();
});
client_socket
=
task_queue
.
front
();
task_queue
.
pop
();
}
char
buffer
[
BUFFER_SIZE
]
=
{
0
};
ssize_t
bytes_received
=
read
(
client_socket
,
buffer
,
BUFFER_SIZE
);
if
(
bytes_received
<=
0
)
{
close
(
client_socket
);
continue
;
}
std
::
string
request
(
buffer
);
if
(
request
.
back
()
!=
';'
)
{
std
::
cerr
<<
"Invalid request format"
<<
std
::
endl
;
Request
*
parseRequest
(
const
char
*
buffer
)
{
continue
;
// Create a new Request struct
Request
*
req
=
new
Request
();
// Copy the input buffer to a mutable string for tokenization
char
*
input
=
strdup
(
buffer
);
// Duplicate the buffer
if
(
!
input
)
{
return
nullptr
;
// Handle memory allocation failure
}
// Tokenize the input string using ',' and ';' as delimiters
char
*
token
=
strtok
(
input
,
",;"
);
if
(
token
)
{
// First token is the operation
req
->
operation
=
token
[
0
];
// Extract the first character (s, g, or d)
// Second token is the key
token
=
strtok
(
nullptr
,
",;"
);
if
(
token
)
{
req
->
key
=
token
;
// Third token is the value (only for store operation)
if
(
req
->
operation
==
's'
)
{
token
=
strtok
(
nullptr
,
",;"
);
if
(
token
)
{
req
->
value
=
token
;
}
}
}
}
}
// Free the duplicated input string
free
(
input
);
return
req
;
}
void
handle_client
(
int
client_socket
)
{
char
buffer
[
BUFFER_SIZE
]
=
{
0
};
// Nachricht vom Client empfangen
ssize_t
bytes_received
=
read
(
client_socket
,
buffer
,
BUFFER_SIZE
);
if
(
bytes_received
>
0
)
{
//std::cout << "Client: " << buffer << std::endl;
Request
*
request
=
parseRequest
(
buffer
);
std
::
string
response
;
std
::
string
response
;
char
operation
=
request
[
0
];
size_t
first_comma
=
request
.
find
(
','
,
1
);
if
(
request
->
operation
==
STORE_OPERATION
){
if
(
first_comma
==
std
::
string
::
npos
)
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
mtx
);
response
=
"ERROR: Invalid format;"
;
response
=
"Key "
+
request
->
key
+
" Not Found for [get]"
;
}
else
{
DB
.
push_back
(
request
);
std
::
string
key
=
request
.
substr
(
2
,
first_comma
-
2
);
response
=
"freue dich :)"
;
if
(
operation
==
's'
)
{
// Store operation
}
else
if
(
request
->
operation
==
GET_OPERATION
){
size_t
second_comma
=
request
.
find
(
','
,
first_comma
+
1
);
std
::
lock_guard
<
std
::
mutex
>
lock
(
mtx
);
if
(
second_comma
==
std
::
string
::
npos
)
{
for
(
Request
*
current
:
DB
)
{
response
=
"ERROR: Invalid format;"
;
if
(
current
->
key
==
request
->
key
){
}
else
{
response
=
current
->
value
;
std
::
string
value
=
request
.
substr
(
first_comma
+
1
,
second_comma
-
first_comma
-
1
);
break
;
std
::
lock_guard
<
std
::
mutex
>
lock
(
store_mutex
);
store
[
key
]
=
value
;
response
=
"STORED;"
;
}
}
else
if
(
operation
==
'g'
)
{
// Get operation
std
::
lock_guard
<
std
::
mutex
>
lock
(
store_mutex
);
auto
it
=
store
.
find
(
key
);
if
(
it
!=
store
.
end
())
{
response
=
"VALUE,"
+
it
->
second
+
";"
;
}
else
{
response
=
"NOT_FOUND;"
;
}
}
}
else
if
(
operation
==
'd'
)
{
// Delete operation
}
std
::
lock_guard
<
std
::
mutex
>
lock
(
store_mutex
);
}
else
if
(
request
->
operation
==
DELETE_OPERATION
){
if
(
store
.
erase
(
key
)
>
0
)
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
mtx
);
response
=
"DELETED;"
;
response
=
"Key "
+
request
->
key
+
" Not Found for [delete]"
;
}
else
{
for
(
size_t
i
=
0
;
i
<
DB
.
size
();
i
++
){
response
=
"NOT_FOUND;"
;
if
(
DB
[
i
]
->
key
==
request
->
key
){
delete
DB
[
i
];
DB
.
erase
(
DB
.
begin
()
+
i
);
response
=
"Key "
+
request
->
key
+
" is deleted"
;
break
;
}
}
}
else
{
response
=
"ERROR: Unknown operation;"
;
}
}
}
else
{
response
=
"bad request -_____- !"
;
}
}
send
(
client_socket
,
response
.
c_str
(),
response
.
length
(),
0
);
// send Response
send
(
client_socket
,
response
.
c_str
(),
strlen
(
response
.
c_str
()),
0
);
}
}
// Socket schließen
close
(
client_socket
);
}
}
int
main
()
{
int
main
()
{
int
server_fd
,
epoll_fd
;
int
server_fd
,
client_socket
;
struct
sockaddr_in
address
{}
;
struct
sockaddr_in
address
;
socklen_t
addrlen
=
sizeof
(
address
);
socklen_t
addrlen
=
sizeof
(
address
);
std
::
vector
<
std
::
thread
>
threads
;
//
Server-
Socket erstellen
// Socket erstellen
server_fd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
server_fd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
server_fd
==
-
1
)
{
if
(
server_fd
==
-
1
)
{
perror
(
"Socket failed"
);
perror
(
"Socket failed"
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
int
opt
=
1
;
// Serveradresse festlegen
setsockopt
(
server_fd
,
SOL_SOCKET
,
SO_REUSEADDR
,
&
opt
,
sizeof
(
opt
));
address
.
sin_family
=
AF_INET
;
address
.
sin_family
=
AF_INET
;
address
.
sin_addr
.
s_addr
=
INADDR_ANY
;
address
.
sin_addr
.
s_addr
=
INADDR_ANY
;
address
.
sin_port
=
htons
(
PORT
);
address
.
sin_port
=
htons
(
PORT
);
// Socket an Port binden
if
(
bind
(
server_fd
,
(
struct
sockaddr
*
)
&
address
,
sizeof
(
address
))
<
0
)
{
if
(
bind
(
server_fd
,
(
struct
sockaddr
*
)
&
address
,
sizeof
(
address
))
<
0
)
{
perror
(
"Bind failed"
);
perror
(
"Bind failed"
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
if
(
listen
(
server_fd
,
SOMAXCONN
)
<
0
)
{
// Server lauscht auf eingehende Verbindungen
if
(
listen
(
server_fd
,
5
)
<
0
)
{
perror
(
"Listen failed"
);
perror
(
"Listen failed"
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
// Epoll erstellen
std
::
cout
<<
"Server listening on port "
<<
PORT
<<
std
::
endl
;
epoll_fd
=
epoll_create1
(
0
);
if
(
epoll_fd
==
-
1
)
{
perror
(
"Epoll create failed"
);
exit
(
EXIT_FAILURE
);
}
struct
epoll_event
event
{};
event
.
events
=
EPOLLIN
;
event
.
data
.
fd
=
server_fd
;
if
(
epoll_ctl
(
epoll_fd
,
EPOLL_CTL_ADD
,
server_fd
,
&
event
)
==
-
1
)
{
perror
(
"Epoll control failed"
);
exit
(
EXIT_FAILURE
);
}
std
::
vector
<
std
::
thread
>
thread_pool
;
for
(
int
i
=
0
;
i
<
THREAD_POOL_SIZE
;
i
++
)
{
thread_pool
.
emplace_back
(
worker_thread
);
}
struct
epoll_event
events
[
MAX_EVENTS
];
while
(
true
)
{
while
(
true
)
{
int
num_events
=
epoll_wait
(
epoll_fd
,
events
,
MAX_EVENTS
,
-
1
);
client_socket
=
accept
(
server_fd
,
(
struct
sockaddr
*
)
&
address
,
&
addrlen
);
if
(
num_events
==
-
1
)
{
perror
(
"Epoll wait failed"
);
if
(
client_socket
<
0
)
{
exit
(
EXIT_FAILURE
);
perror
(
"Accept failed"
);
continue
;
}
}
for
(
int
i
=
0
;
i
<
num_events
;
i
++
)
{
std
::
cout
<<
"New client connected"
<<
std
::
endl
;
if
(
events
[
i
].
data
.
fd
==
server_fd
)
{
int
client_socket
=
accept
(
server_fd
,
(
struct
sockaddr
*
)
&
address
,
&
addrlen
);
// Starte neuen Thread für den Client
if
(
client_socket
<
0
)
{
threads
.
emplace_back
(
handle_client
,
client_socket
);
perror
(
"Accept failed"
);
}
continue
;
}
struct
epoll_event
client_event
{};
client_event
.
events
=
EPOLLIN
;
client_event
.
data
.
fd
=
client_socket
;
if
(
epoll_ctl
(
epoll_fd
,
EPOLL_CTL_ADD
,
client_socket
,
&
client_event
)
==
-
1
)
{
// Alle Threads beenden
perror
(
"Epoll add client failed"
);
for
(
auto
&
t
:
threads
)
{
close
(
client_socket
);
t
.
join
();
}
}
else
{
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
queue_mutex
);
task_queue
.
push
(
events
[
i
].
data
.
fd
);
}
cv
.
notify_one
();
}
}
}
}
close
(
server_fd
);
close
(
server_fd
);
return
0
;
return
0
;
}
}
This diff is collapsed.
Click to expand it.
prak3/src/test.cpp
+
80
−
0
View file @
7b1bd202
#include
<iostream>
#include
<string>
#include
<cstring>
// for strtok and strchr
struct
Request
{
char
operation
;
// Operation: 's' (store), 'g' (get), 'd' (delete)
std
::
string
key
;
// Key
std
::
string
value
;
// Value (only for store operation)
};
Request
*
parseRequest
(
const
char
*
buffer
)
{
// Create a new Request struct
Request
*
req
=
new
Request
();
// Copy the input buffer to a mutable string for tokenization
char
*
input
=
strdup
(
buffer
);
// Duplicate the buffer
if
(
!
input
)
{
return
nullptr
;
// Handle memory allocation failure
}
// Tokenize the input string using ',' and ';' as delimiters
char
*
token
=
strtok
(
input
,
",;"
);
if
(
token
)
{
// First token is the operation
req
->
operation
=
token
[
0
];
// Extract the first character (s, g, or d)
// Second token is the key
token
=
strtok
(
nullptr
,
",;"
);
if
(
token
)
{
req
->
key
=
token
;
// Third token is the value (only for store operation)
if
(
req
->
operation
==
's'
)
{
token
=
strtok
(
nullptr
,
",;"
);
if
(
token
)
{
req
->
value
=
token
;
}
}
}
}
// Free the duplicated input string
free
(
input
);
return
req
;
}
int
main
()
{
// Test cases
const
char
*
storeRequest
=
"s,myKey,myValue;"
;
const
char
*
getRequest
=
"g,myKey;"
;
const
char
*
deleteRequest
=
"d,myKey;"
;
// Parse requests
Request
*
storeReq
=
parseRequest
(
storeRequest
);
Request
*
getReq
=
parseRequest
(
getRequest
);
Request
*
deleteReq
=
parseRequest
(
deleteRequest
);
// Print parsed requests
if
(
storeReq
)
{
std
::
cout
<<
"Store Request: Operation="
<<
storeReq
->
operation
<<
", Key="
<<
storeReq
->
key
<<
", Value="
<<
storeReq
->
value
<<
std
::
endl
;
delete
storeReq
;
}
if
(
getReq
)
{
std
::
cout
<<
"Get Request: Operation="
<<
getReq
->
operation
<<
", Key="
<<
getReq
->
key
<<
std
::
endl
;
delete
getReq
;
}
if
(
deleteReq
)
{
std
::
cout
<<
"Delete Request: Operation="
<<
deleteReq
->
operation
<<
", Key="
<<
deleteReq
->
key
<<
std
::
endl
;
delete
deleteReq
;
}
return
0
;
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment