Skip to content

Commit 298ab22

Browse files
committed
add berkeley server-clients
1 parent c543066 commit 298ab22

File tree

5 files changed

+372
-0
lines changed

5 files changed

+372
-0
lines changed

Diff for: p1_berkeley_server_clients/Makefile

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
compile:
2+
g++ server.cpp -o server -std=c++11
3+
g++ client.cpp -o client -std=c++11
4+
5+
server:
6+
g++ server.cpp -o server -std=c++11
7+
8+
client:
9+
g++ client.cpp -o client -std=c++11
10+
11+
clean:
12+
rm server client

Diff for: p1_berkeley_server_clients/client

44.3 KB
Binary file not shown.

Diff for: p1_berkeley_server_clients/client.cpp

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#include <stdio.h>
2+
#include <sys/socket.h>
3+
#include <arpa/inet.h>
4+
#include <unistd.h>
5+
#include <string.h>
6+
#include <iostream>
7+
#include <stdlib.h> /* srand, rand */
8+
#include <cstdlib>
9+
#include <ctime>
10+
#include <vector>
11+
12+
#define PORT 8080
13+
14+
using namespace std;
15+
16+
17+
18+
// function for string delimiter
19+
vector<string> split(string s, string delimiter) {
20+
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
21+
string token;
22+
vector<string> res;
23+
24+
while ((pos_end = s.find (delimiter, pos_start)) != string::npos) {
25+
token = s.substr (pos_start, pos_end - pos_start);
26+
pos_start = pos_end + delim_len;
27+
res.push_back (token);
28+
}
29+
30+
res.push_back (s.substr (pos_start));
31+
return res;
32+
}
33+
34+
int main(int argc, char const *argv[])
35+
{
36+
37+
srand((unsigned int)time(NULL)); // avoid always same output of rand()
38+
float client_local_clock = rand() % 10; // range from 0 to 9
39+
printf("Client starts. Client pid is %d \n", getpid());
40+
printf("Client local clock is %f \n\n", client_local_clock);
41+
42+
int client_socket_fd, valread;
43+
char client_read_buffer[1024] = {0};
44+
45+
struct sockaddr_in server_addr;
46+
server_addr.sin_family = AF_INET;
47+
// server_addr.sin_addr.s_addr = inet_addr(argv[1]); // hardcode to 127.0.0.1
48+
server_addr.sin_port = htons(PORT);
49+
50+
51+
52+
53+
// Creating socket file descriptor (IPv4, TCP, IP)
54+
if ((client_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
55+
{
56+
printf("\n Client: Socket creation error \n");
57+
return -1;
58+
}
59+
60+
61+
// Converting IPv4 and IPv6 addresses from text to binary form,
62+
// from character string src into a network
63+
// address structure in the af address family, then copies the
64+
// network address structure to dst.
65+
if(inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr)<=0)
66+
{
67+
printf("\nClient: Invalid address/ Address not supported \n");
68+
return -1;
69+
}
70+
71+
// Connecting server, return 0 with success, return -1 with error
72+
if (connect(client_socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
73+
{
74+
printf("\nClient: Connection Failed \n");
75+
return -1;
76+
}
77+
78+
char server_ip[INET_ADDRSTRLEN]="";
79+
inet_ntop(AF_INET, &server_addr.sin_addr, server_ip, INET_ADDRSTRLEN);
80+
printf("Client: connected server(%s:%d). \n", server_ip, ntohs(server_addr.sin_port));
81+
printf("\n\n");
82+
83+
//
84+
// first round communicattion
85+
//
86+
87+
// receiving form server
88+
valread = read( client_socket_fd , client_read_buffer, 1024);
89+
printf("Client: read: '%s'\n",client_read_buffer );
90+
91+
// convert char array to string
92+
string recv_msg = string(client_read_buffer);
93+
94+
// reply according to what client receive
95+
if (strcmp(client_read_buffer, "Hello from server, please tell me your local clock value.") == 0) {
96+
// prepare msg
97+
string msg_str = "Hello from client, my local clock value is " + to_string(client_local_clock);
98+
char msg_char_array[msg_str.length() + 1];
99+
strcpy(msg_char_array, msg_str.c_str());
100+
// sending a message to server
101+
send(client_socket_fd , &msg_char_array , strlen(msg_char_array) , 0 );
102+
printf("Client: sent message: '%s'\n", msg_char_array);
103+
}
104+
105+
//
106+
// second round communicattion
107+
//
108+
109+
// receiving form server
110+
valread = read( client_socket_fd , client_read_buffer, 1024);
111+
printf("Client: read: '%s'\n",client_read_buffer );
112+
113+
// convert char array to string
114+
recv_msg = string(client_read_buffer);
115+
116+
if (recv_msg.find("From server, your clock adjustment offset is") != string::npos){ // if latter is a substring of former
117+
string substr_after_lastbutone_space;
118+
string substr_after_last_space;
119+
vector<string> split_str = split(recv_msg, " ");
120+
substr_after_lastbutone_space = split_str[ split_str.size() - 2 ];
121+
substr_after_last_space = split_str[ split_str.size() - 1 ];
122+
123+
cout << "Client: received local clock adjustment offset (string) is " << substr_after_lastbutone_space << " " << substr_after_last_space << endl;
124+
float substr_after_last_space_f = stof(substr_after_last_space);
125+
cout << "Client: received local clock adjustment offset (float) is " << substr_after_lastbutone_space << " " << substr_after_last_space_f << endl;
126+
127+
char oper_char_array[substr_after_lastbutone_space.length() + 1];
128+
strcpy(oper_char_array, substr_after_lastbutone_space.c_str());
129+
if (strcmp(oper_char_array, "add") == 0 ){
130+
client_local_clock += substr_after_last_space_f;
131+
}else if (strcmp(oper_char_array, "minus") == 0 ){
132+
client_local_clock -= substr_after_last_space_f;
133+
}
134+
135+
printf("Client local clock is %f \n\n", client_local_clock);
136+
}
137+
138+
139+
140+
141+
142+
close(client_socket_fd);
143+
return 0;
144+
}

Diff for: p1_berkeley_server_clients/server

66.9 KB
Binary file not shown.

Diff for: p1_berkeley_server_clients/server.cpp

+216
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
#include <iostream>
2+
#include <iomanip>
3+
#include <cstdlib>
4+
#include <unistd.h>
5+
#include <stdio.h>
6+
#include <sys/socket.h>
7+
#include <stdlib.h>
8+
#include <netinet/in.h>
9+
#include <string.h>
10+
#include <arpa/inet.h>
11+
#include <vector>
12+
#include <cstdlib>
13+
#include <ctime>
14+
15+
#define PORT 8080
16+
17+
using namespace std;
18+
19+
// function for string delimiter
20+
vector<string> split(string s, string delimiter) {
21+
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
22+
string token;
23+
vector<string> res;
24+
25+
while ((pos_end = s.find (delimiter, pos_start)) != string::npos) {
26+
token = s.substr (pos_start, pos_end - pos_start);
27+
pos_start = pos_end + delim_len;
28+
res.push_back (token);
29+
}
30+
31+
res.push_back (s.substr (pos_start));
32+
return res;
33+
}
34+
35+
36+
int main(int argc, char *argv[])
37+
{
38+
// /* deal with input arguments*/
39+
// std::cout << "print arguments:\nargc == " << argc << '\n';
40+
// for(int ndx{}; ndx != argc; ++ndx) {
41+
// std::cout << "argv[" << ndx << "] == " << argv[ndx] << '\n';
42+
// }
43+
// std::cout << "argv[" << argc << "] == "
44+
// << static_cast<void*>(argv[argc]) << '\n';
45+
46+
srand((unsigned int)time(NULL)); // avoid always same output of rand()
47+
float server_local_clock = rand() % 10; // range from 0 to 9
48+
vector<float> clients_local_clocks;
49+
printf("Sever starts. Server pid is %d \n", getpid());
50+
printf("Server local clock is %f \n\n", server_local_clock);
51+
52+
53+
54+
// Socket Cite: https://www.geeksforgeeks.org/socket-programming-cc/?ref=lbp
55+
int server_socket_fd, new_socket, valread;
56+
vector<int> client_sockets;
57+
vector<string> client_ips;
58+
vector<int> client_ports;
59+
struct sockaddr_in server_address;
60+
server_address.sin_family = AF_INET; // IPv4
61+
server_address.sin_addr.s_addr = INADDR_ANY; // localhost
62+
server_address.sin_port = htons( PORT ); // 8080
63+
int opt = 1; // for setsockopt
64+
65+
// Creating socket file descriptor (IPv4, TCP, IP)
66+
if ((server_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
67+
{
68+
perror("Server: socket failed");
69+
exit(EXIT_FAILURE);
70+
}
71+
72+
// Optional: it helps in reuse of address and port. Prevents error such as: “address already in use”.
73+
if (setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
74+
&opt, sizeof(opt)))
75+
{
76+
perror("Server: setsockopt");
77+
exit(EXIT_FAILURE);
78+
}
79+
80+
// Forcefully attaching socket to the port 8080
81+
if (bind(server_socket_fd, (struct sockaddr *)&server_address,
82+
sizeof(server_address))<0)
83+
{
84+
perror("Server: bind failed");
85+
exit(EXIT_FAILURE);
86+
}
87+
88+
// Putting the server socket in a passive mode, waiting for the client to approach the server to make a connection
89+
// The backlog=7, defines the maximum length to which the queue of pending connections for sockfd may grow.
90+
// If a connection request arrives when the queue is full, the client may receive an error with an indication of ECONNREFUSED.
91+
if (listen(server_socket_fd, 7) < 0)
92+
{
93+
perror("Server: listen");
94+
exit(EXIT_FAILURE);
95+
}
96+
printf("Server: server is listening ...\n\nYou can open one or multiple new terminal windows now to run ./client\n");
97+
int clients_ctr = 0;
98+
99+
100+
// Setting up buffer for receiving msg
101+
char recv_buf[65536];
102+
memset(recv_buf, '\0', sizeof(recv_buf));
103+
104+
int in_client_enough = 0;
105+
while ( in_client_enough == 0) { // block on accept() until positive fd or error
106+
struct sockaddr_in client_addr;
107+
socklen_t length = sizeof(client_addr);
108+
// Extracting the first connection request on the queue of pending connections for the listening socket (server_socket_fd)
109+
// Creates a new connected socket, and returns a new file descriptor referring to that socket
110+
if ((new_socket = accept(server_socket_fd, (struct sockaddr *)&client_addr,
111+
(socklen_t*)&length))<0)
112+
{
113+
perror("Server: accept");
114+
exit(EXIT_FAILURE);
115+
}
116+
117+
clients_ctr ++;
118+
printf("\nYou have connected %d client(s) now.", clients_ctr);
119+
120+
// converting the network address structure src in the af address family into a character string.
121+
char client_ip[INET_ADDRSTRLEN] = "";
122+
inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
123+
printf("Server: new client accepted. client ip and port: %s:%d\n", client_ip, ntohs(client_addr.sin_port));
124+
125+
126+
// store new client connection into array
127+
client_sockets.push_back(new_socket);
128+
client_ips.push_back(client_ip);
129+
client_ports.push_back(ntohs(client_addr.sin_port));
130+
131+
printf("current connected clients amount is %d \n", int(client_sockets.size()) );
132+
133+
cout << "Do you have enought clients? (please input '1' for yes, '0' for no):" ;
134+
cin >> in_client_enough;
135+
if (in_client_enough == 0){
136+
cout << "OK. Please continute opening one or multiple new terminal windows to run ./client\n" << endl;
137+
}else if (in_client_enough != 1){
138+
cout << "Unrecognized input has been considered as 0. You can create one more client.\n" << endl;
139+
in_client_enough = 0;
140+
}
141+
}
142+
143+
144+
printf("\nClients creation finished! There are totally %d connected clients.\n", int(client_sockets.size()) );
145+
printf("Asking all clients to report their local clock value ... \n\n\n");
146+
147+
148+
for (int i = 0; i < client_sockets.size(); i++){
149+
// sending a message to client
150+
const char *msg = "Hello from server, please tell me your local clock value.";
151+
send(client_sockets[i] , msg , strlen(msg) , 0 );
152+
printf("Server: sent to client(%s:%d): '%s'\n", client_ips[i].c_str(), client_ports[i], msg);
153+
154+
155+
// receiving
156+
while(recv(client_sockets[i], recv_buf, sizeof(recv_buf), 0) > 0 ){
157+
printf("Server: recv from client(%s:%d): '%s' \n", client_ips[i].c_str(), client_ports[i], recv_buf);
158+
159+
// convert char array to string
160+
string recv_msg = string(recv_buf);
161+
162+
if (recv_msg.find("Hello from client, my local clock value is") != string::npos){
163+
string substr_after_last_space;
164+
vector<string> split_str = split(recv_msg, " ");
165+
substr_after_last_space = split_str[ split_str.size() - 1 ];
166+
167+
cout << "Server: received client local clock (string) is " << substr_after_last_space << endl;
168+
float substr_after_last_space_f = stof(substr_after_last_space);
169+
cout << "Server: received client local clock (float) is " << substr_after_last_space_f << endl;
170+
171+
clients_local_clocks.push_back(substr_after_last_space_f);
172+
}
173+
174+
memset(recv_buf, '\0', strlen(recv_buf));
175+
break;
176+
}
177+
}
178+
179+
printf("\n\n");
180+
181+
// average clock values
182+
float all_clock_sum = server_local_clock;
183+
for (int i = 0; i < clients_local_clocks.size(); i++){
184+
all_clock_sum += clients_local_clocks[i];
185+
}
186+
float avg_clock = all_clock_sum / (client_sockets.size() + 1);
187+
188+
// tell clients how to adjust
189+
for (int i = 0; i < client_sockets.size(); i++){
190+
// prepare msg
191+
float offset = clients_local_clocks[i] - avg_clock;
192+
string operation;
193+
if (offset >= 0){
194+
operation = "minus";
195+
}else{
196+
operation = "add";
197+
offset = 0 - offset;
198+
}
199+
string msg_str = "From server, your clock adjustment offset is " + operation + " " + to_string(offset);
200+
char msg_char_array[msg_str.length() + 1];
201+
strcpy(msg_char_array, msg_str.c_str());
202+
// sending a message to client
203+
send(client_sockets[i] , &msg_char_array , strlen(msg_char_array) , 0 );
204+
printf("Server: sent to client(%s:%d): '%s'\n", client_ips[i].c_str(), client_ports[i], msg_char_array);
205+
206+
}
207+
208+
// adjust self
209+
server_local_clock += avg_clock - server_local_clock;
210+
printf("\n\nServer new local clock is %f \n\n", server_local_clock);
211+
212+
213+
printf("Server: server stopped. \n");
214+
close(server_socket_fd);
215+
return 0;
216+
}

0 commit comments

Comments
 (0)