Skip to content

Commit 3fe656c

Browse files
author
Anton Yarkov
committed
Examples of sync and multiplexed async tcp server and client which implements training algorithm/protocol - getting and posting Astrological forecasts.
1 parent 8a17484 commit 3fe656c

File tree

6 files changed

+1349
-0
lines changed

6 files changed

+1349
-0
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <strings.h>
5+
#include <sys/types.h>
6+
#include <sys/socket.h>
7+
#include <arpa/inet.h>
8+
#include <netinet/in.h>
9+
#include <fcntl.h>
10+
#include <netdb.h>
11+
#include <unistd.h>
12+
13+
#define PORTNUM 1500 // Port > 1024 because program will not work not as root.
14+
15+
// Task:
16+
// Create a test TCP-client which sends commands to TCP-server:
17+
// HOROSCOPE - get astrological forecasts from server.
18+
// STARS SAY - send forecast to server.
19+
20+
// Function read number of bytes and return it. It is necessary to use such a function for read,
21+
// because system call recv may return not full response and it will be necessary to read in loop.
22+
ssize_t receive_all(int fd, char *buf, size_t len)
23+
{
24+
size_t pos = 0;
25+
26+
while (pos < len)
27+
{
28+
// Buffer returned by system call recv - is not the string, so we can't use string functions with it.
29+
ssize_t received = recv(fd, buf + pos, len - pos, MSG_NOSIGNAL); // Receive byte by byte.
30+
31+
if (received == -1) return -1;
32+
else if (received == 0) return pos;
33+
else if (received > 0) pos += received;
34+
}
35+
36+
return pos;
37+
}
38+
39+
void main(int argc, char **argv)
40+
{
41+
struct hostent *hp;
42+
if ((hp = gethostbyname(argv[1])) == 0)
43+
{
44+
perror("Error of calling gethostbyname"); /* or strerror */
45+
exit(1);
46+
}
47+
48+
struct sockaddr_in serv_addr;
49+
memset(&serv_addr, '\0', sizeof(serv_addr));
50+
bcopy(hp->h_addr_list[0], &serv_addr.sin_addr, hp->h_length);
51+
serv_addr.sin_family = hp->h_addrtype;
52+
serv_addr.sin_port = htons(PORTNUM);
53+
54+
int sockfd = -1;
55+
if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
56+
{
57+
perror("Error of calling socket");
58+
exit(1);
59+
}
60+
61+
fprintf(stderr, "Server address: %s\n", inet_ntoa(serv_addr.sin_addr));
62+
63+
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
64+
{
65+
perror("Error of calling connect");
66+
exit(1);
67+
}
68+
69+
int testStep = (*argv[2]) - '0';
70+
printf("testStep: %d\n", testStep);
71+
72+
if (testStep == 1)
73+
{
74+
// TEST1. Set some HOROSCOPE.
75+
76+
char setzodiak[] = "STARS SAY Aries ";
77+
int sent = send(sockfd, setzodiak, strlen(setzodiak) + 1, MSG_NOSIGNAL);
78+
printf("Sent to server: %s, %d bytes\n", setzodiak, sent);
79+
80+
char desc[] = "Some of my descriptions here. ";
81+
sent = send(sockfd, desc, strlen(desc) + 1, MSG_NOSIGNAL);
82+
printf("Sent to server: %s, %d bytes\n", desc, sent);
83+
84+
char thanks[10];
85+
memset(thanks, '\0', 10);
86+
int received = receive_all(sockfd, thanks, 10);
87+
printf("Received from server: %d bytes\n", received);
88+
if (received > 0)
89+
{
90+
printf("Received from server: %s\n", thanks);
91+
}
92+
}
93+
else if (testStep == 2)
94+
{
95+
// TEST2. Get HOROSCOPE which was set.
96+
char getzodiak[] = "HOROSCOPE Aries ";
97+
int sent = send(sockfd, getzodiak, strlen(getzodiak) + 1, MSG_NOSIGNAL);
98+
printf("Sent to server: %s, %d bytes\n", getzodiak, sent);
99+
100+
char horoscope[80];
101+
memset(horoscope, '\0', 80);
102+
int received = receive_all(sockfd, horoscope, 80);
103+
printf("Received from server: %d bytes\n", received);
104+
if (received > 0)
105+
{
106+
printf("Received from server: %s\n", horoscope);
107+
}
108+
}
109+
else if (testStep == 3)
110+
{
111+
// TEST3. Good COMMAND, Bad attributes.
112+
char getzodiak[] = "HOROSCOPE Abracadabra";
113+
int sent = send(sockfd, getzodiak, strlen(getzodiak) + 1, MSG_NOSIGNAL);
114+
printf("Sent to server: %s, %d bytes\n", getzodiak, sent);
115+
116+
char denied[10];
117+
memset(denied, '\0', 10);
118+
int received = receive_all(sockfd, denied, 10);
119+
printf("Received from server: %d bytes\n", received);
120+
if (received > 0)
121+
{
122+
printf("Received from server: %s\n", denied);
123+
}
124+
}
125+
else if (testStep == 4)
126+
{
127+
// TEST4. Wrong COMMAND.
128+
char wrongCommand[] = "ABRA CADABRA BOOM BOOM";
129+
int sent = send(sockfd, wrongCommand, strlen(wrongCommand) + 1, MSG_NOSIGNAL);
130+
printf("Sent to server: %s, %d bytes\n", wrongCommand, sent);
131+
132+
char denied[10];
133+
memset(denied, '\0', 10);
134+
int received = receive_all(sockfd, denied, 10);
135+
printf("Received from server: %d bytes\n", received);
136+
}
137+
138+
close(sockfd);
139+
printf("Client off!\n\n"); \
140+
}
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <sys/types.h>
5+
#include <sys/socket.h>
6+
#include <arpa/inet.h>
7+
#include <fcntl.h>
8+
#include <netdb.h>
9+
#include <unistd.h>
10+
11+
#define PORTNUM 1500 // Port > 1024 because program will not work not as root.
12+
13+
// Task:
14+
// Create a TCP-server which returns astrological forecasts as a response to client command HOROSCOPE.
15+
// It should remember forecast on a STARS SAY command from client. Server should handle possible errors.
16+
17+
// Function read number of bytes and return it. It is necessary to use such a function for read,
18+
// because system call recv may return not full response and it will be necessary to read in loop.
19+
ssize_t receive_all(int fd, char *buf, size_t len)
20+
{
21+
size_t pos = 0;
22+
23+
while (pos < len)
24+
{
25+
// Buffer returned by system call recv - is not the string, so we can't use string functions with it.
26+
ssize_t received = recv(fd, buf + pos, len - pos, MSG_NOSIGNAL); // Receive byte by byte.
27+
28+
if (received == -1) return -1;
29+
else if (received == 0) return pos;
30+
else if (received > 0) pos += received;
31+
}
32+
33+
return pos;
34+
}
35+
36+
void main()
37+
{
38+
printf("ASTRO Server PID -- %d.\n", getpid());
39+
40+
// Create socket
41+
int sockfd = -1;
42+
if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
43+
{
44+
perror("Error of calling socket"); /* or strerror */
45+
exit(1);
46+
}
47+
48+
// For UDP SO_REUSEADDR may mean some problems...
49+
int optval = 1;
50+
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) == -1)
51+
{
52+
perror("Error of calling setsockopt");
53+
exit(1);
54+
}
55+
56+
// Set address
57+
struct sockaddr_in serv_addr;
58+
memset(&serv_addr, '\0', sizeof(serv_addr));
59+
serv_addr.sin_family = AF_INET;
60+
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0 (INADDR_LOOPBACK - 127.0.0.1)
61+
62+
// Change bytes order to network'
63+
int nport = htons((int)PORTNUM);
64+
serv_addr.sin_port = nport;
65+
66+
// Link socket with address
67+
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
68+
{
69+
perror("Error of calling bind");
70+
exit(1);
71+
}
72+
73+
fprintf(stderr, "Server is ready: %s\n", inet_ntoa(serv_addr.sin_addr));
74+
75+
// Server is ready to get SOMAXCONN connection requests (128).
76+
// This is *SHOULD* be enought to call accept and create child process.
77+
if (listen(sockfd, SOMAXCONN) == -1)
78+
{
79+
perror("Error of calling listen");
80+
exit(1);
81+
}
82+
83+
struct sockaddr_in clnt_addr;
84+
socklen_t addrlen = sizeof(clnt_addr);
85+
memset(&clnt_addr, '\0', sizeof(clnt_addr));
86+
87+
int newsocket = -1;
88+
89+
char zodiaks[12][12] = { "Aries ", "Taurus ", "Gemini ", "Cancer ",
90+
"Leo ", "Virgo ", "Libra ", "Scorpio ", "Sagittarius",
91+
"Capricorn ", "Aquarius ", "Pisces " };
92+
93+
char descriptions[12][80] = { "", "", "", "", "", "", "", "", "", "", "", "" };
94+
95+
char thanks[] = "THANKS!";
96+
char denied[] = "DENIED!";
97+
char sorry[] = "SORRY!";
98+
99+
while (1)
100+
{
101+
if ((newsocket = accept(sockfd, (struct sockaddr *)&clnt_addr, &addrlen)) == -1)
102+
{
103+
perror("Error of calling accept");
104+
exit(1);
105+
}
106+
107+
printf("Client = %s \n", inet_ntoa(clnt_addr.sin_addr));
108+
109+
char command[22];
110+
memset(command, '\0', 22);
111+
int received = receive_all(newsocket, command, 22);
112+
113+
printf("Received from client: %s, %d bytes\n", command, received);
114+
115+
if (received == 22)// && command[21] == '\n')
116+
{
117+
// Get znak zodiak
118+
char zodiak[11];
119+
for (int i = 10; i < 21; i++)
120+
{
121+
zodiak[i - 10] = command[i];
122+
}
123+
124+
printf("Received from client: zodiak %s\n", zodiak);
125+
126+
// Find it in array.
127+
int desc_index = -1;
128+
for (int i = 0; i < 12; i++)
129+
{
130+
if (strncmp(zodiaks[i], zodiak, 12) == 0)
131+
{
132+
desc_index = i;
133+
break;
134+
}
135+
}
136+
137+
printf("Position in array of zodiaks: %d\n", desc_index);
138+
139+
if (strncmp(command, "STARS SAY ", 10) == 0)
140+
{
141+
// If found, get description.
142+
if (desc_index > -1)
143+
{
144+
// Receive 80 bytes of description.
145+
char desc[80];
146+
memset(desc, '\0', 80);
147+
148+
int received_dest = receive_all(newsocket, desc, 80);
149+
150+
if (received_dest > 0)
151+
{
152+
memcpy(descriptions[desc_index], desc, received_dest);
153+
}
154+
155+
printf("Received from client: %s, %d bytes\n", desc, received_dest);
156+
157+
// Send thanks
158+
int sent = send(newsocket, thanks, strlen(thanks) + 1, MSG_NOSIGNAL);
159+
printf("Sent to client: %s, %d bytes\n", thanks, sent);
160+
}
161+
else
162+
{
163+
int sent = send(newsocket, denied, strlen(denied) + 1, MSG_NOSIGNAL);
164+
printf("Sent to client: %s, %d bytes\n", denied, sent);
165+
}
166+
}
167+
else if (strncmp(command, "HOROSCOPE ", 10) == 0)
168+
{
169+
// Send 80 bytes description
170+
if (desc_index > -1)
171+
{
172+
if (strlen(descriptions[desc_index]) > 1)
173+
{
174+
int sent = send(newsocket, descriptions[desc_index], sizeof(descriptions[desc_index]), MSG_NOSIGNAL);
175+
printf("Sent to client: %s, %d bytes\n", descriptions[desc_index], sent);
176+
}
177+
else
178+
{
179+
int sent = send(newsocket, sorry, strlen(sorry) + 1, MSG_NOSIGNAL);
180+
printf("Sent to client: %s, %d bytes\n", sorry, sent);
181+
}
182+
}
183+
else
184+
{
185+
int sent = send(newsocket, denied, strlen(denied) + 1, MSG_NOSIGNAL);
186+
printf("Sent to client: %s, %d bytes\n", denied, sent);
187+
}
188+
}
189+
}
190+
191+
printf("Connection to client closed!");
192+
close(newsocket);
193+
}
194+
195+
printf("Server stopped!");
196+
close(sockfd);
197+
exit(0);
198+
}

0 commit comments

Comments
 (0)