I am trying to modify some client and server c code so that it takes a user input on the client, send it to the server and the server sends back the corresponding value. I am not very familiar with c programming; therefore, my error is most likely syntax related. Server Code:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
int main(int argc, char *argv[])
{
int listenfd, connfd;
struct sockaddr_in serv_addr;
char sendBuff[1025];
char from_client[1025];
time_t ticks;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', sizeof(sendBuff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(listenfd, 10);
while(1)
{
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
recv(connfd, from_client, sizeof(from_client), 0);
printf("%s", "Letter Recieved\n");
if(from_client == 't')
{
ticks = time(NULL);
snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
write(connfd, sendBuff, strlen(sendBuff));
}
if(from_client == 'n')
{
sendBuff == "Marcus Baker";
send(connfd, sendBuff, sizeof(sendBuff), 0);
}
if(from_client == 'i')
{
sendBuff == "201604543";
send(connfd, sendBuff, sizeof(sendBuff), 0);
}
if(from_client == 'q')
{
return 0;
}
close(connfd);
sleep(1);
}
}
Client Code:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
int sockfd, n = 0;
char letter[1024];
printf("Enter a Character (t, n, i, q): ");
scanf("%c",&letter);
char recvBuff[1024];
struct sockaddr_in serv_addr;
if(argc != 2)
{
printf("\n Usage: %s <ip of server> \n",argv[0]);
return 1;
}
memset(recvBuff, '0',sizeof(recvBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
{
printf("\n inet_pton error occured\n");
return 1;
}
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
{
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF)
{
printf("\n Error : Fputs error\n");
}
}
if(n < 0)
{
printf("\n Read error \n");
}
int toServer = send(sockfd, letter, sizeof(letter), 0);
printf("%s", "Letter Sent\n");
recv(sockfd, recvBuff, sizeof(recvBuff), 0);
printf("%c", recvBuff);
return 0;
}
Any information would be greatly appreciated.
I have tried several different iteration following different stack overflow guides but none seem to work. When I try to compile both pieces of code, I get warnings about the user input potion of the code, something about scanf expects a char*.
CodePudding user response:
I suggest you use a known good client, netcat or socat, then fix the server side first:
- server: You need to deference from_client to compare against the first letter:
if(*from_client == 't') {
and the server returns the right ting:
$ socat - tcp-connect:localhost:5000
t
Wed Feb 1 00:04:36 2023
- server:
sendBuff == "Marcus Baker"
is a comparison and always false, and you just send send as many bytes as needed instead of the whole buffer:
strcpy(sendBuff, "Marcus Baker");
send(connfd, sendBuff, strlen(sendBuff), 0);
and testing it:
n
Marcus Baker
- server:
sendBuff == "201604543"
is a comparison. You have to decide if you want to send it as a string or binary, and if binary if you want a particular encoding (little or big indian). Using a binary and assume the same encoding on both client and server:
memcpy(sendBuff, &(int) { 201604543 }, sizeof(int));
send(connfd, sendBuff, sizeof(int), 0);
and the result is (note the use of od -t d4
to decode the integer value):
socat - tcp-connect:localhost:5000 | od -t d4
i
0000000 201604543
0000004
Now we know the server works (better) so let's start working on the client.
- client: After the client connects it does a
read()
but server is doing arecv()
. Client is expected to write to server so let's just remove this block:
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0) {
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF)
{
printf("\n Error : Fputs error\n");
}
}
if(n < 0) {
printf("\n Read error \n");
}
- server: Now when we send 't' the server responds with time but with a bunch of 0. Going back to server we see it sends the whole buffer so let's fix that:
int n = snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
write(connfd, sendBuff, n);
- client: We still get a bunch of 0 after the time so let's record how much data we get from server and only print that out:
printf("%s", "Letter Sent\n");
ssize_t recvLen = recv(sockfd, recvBuff, sizeof(recvBuff), 0);
printf("%.*s", (int) recvLen, recvBuff);
and now the client reports:
Enter a Character (t, n, i, q): t
Letter Sent
Wed Feb 1 00:26:13 2023
- client: The data we get for 'i' looks weird:
Enter a Character (t, n, i, q): i
Letter Sent
=
This is because it's binary data so we need to decode it:
if(*letter = 'i') {
printf("%d", *(int *) recvBuff);
} else {
// ...
and the output is now as expected:
Enter a Character (t, n, i, q): i
Letter Sent
201604543
- client: 'q' prints doesn't look right:
Letter Sent
808464432
That's because we don't actually expect to get any more data:
printf("%s", "Letter Sent\n");
if(*letter == 'q')
return 0;
- server: When client sends a 'q' we return but this leaves the socket in a timeout state. It's better to close it first:
if(*from_client == 'q') {
close(connfd);
return 0;
}
Here is the programs as changed:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]) {
int sockfd, n = 0;
char letter[1024];
printf("Enter a Character (t, n, i, q): ");
scanf("%c",&letter);
char recvBuff[1024];
struct sockaddr_in serv_addr;
if(argc != 2) {
printf("\n Usage: %s <ip of server> \n",argv[0]);
return 1;
}
memset(recvBuff, '0',sizeof(recvBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Error : Could not create socket \n");
return 1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0) {
printf("\n inet_pton error occured\n");
return 1;
}
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\n Error : Connect Failed \n");
return 1;
}
int toServer = send(sockfd, letter, sizeof(letter), 0);
printf("%s", "Letter Sent\n");
if(*letter == 'q')
return 0;
ssize_t recvLen = recv(sockfd, recvBuff, sizeof(recvBuff), 0);
if(*letter = 'i') {
printf("%d", *(int *) recvBuff);
} else {
printf("%.*s", (int) recvLen, recvBuff);
}
}
server.c:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
int main(int argc, char *argv[]) {
int listenfd, connfd;
struct sockaddr_in serv_addr;
char sendBuff[1025];
char from_client[1025];
time_t ticks;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', sizeof(sendBuff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(listenfd, 10);
for(;;) {
connfd = accept(listenfd, NULL, NULL);
recv(connfd, from_client, sizeof(from_client), 0);
printf("%s", "Letter Recieved\n");
if(*from_client == 't') {
ticks = time(NULL);
int n = snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
write(connfd, sendBuff, n);
}
if(*from_client == 'n') {
strcpy(sendBuff, "Marcus Baker");
send(connfd, sendBuff, strlen(sendBuff), 0);
}
if(*from_client == 'i') {
memcpy(sendBuff, &(int) { 201604543 }, sizeof(int));
send(connfd, sendBuff, sizeof(int), 0);
}
if(*from_client == 'q') {
return 0;
}
close(connfd);
sleep(1);
}
}
- (not fixed) I suggest you extract the shared port number and store in a header file that you can include in both client and server. For example:
#define SERVER_PORT 5000
Then use that constant instead of hard-coding the magic value 5000.
- (not fixed) Audit all calls to ensure you check the return value and handle errors. Failing to do so will waste time.