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*.
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 a recv(). 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.
Related
I am implementing a simple server-client inter-process communication by sending data in binary format from the client to the server. The program is simple: it sends an unsigned number from 1 to 5, once at a time, in binary format. The server reads in the these binary data and converts it back to an unsigned int. However, when I tried to read in on the server size, my binary data was changing. How can I make the reading protocol to read in the data in a format that I sent. I appreciate all helps that I can get! Thank you.
Here is my implementation of the server:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <limits.h>
#include <netdb.h>
#define BUFFER_SIZE 10
int main(int argc, char *argv[])
{
int serv_sock, ret, data_socket;
socklen_t client_sock;
struct sockaddr_in serv_addr;
struct sockaddr_in client_addr;
// char buffer[BUFFER_SIZE];
uint32_t buffer = 0;
FILE *fp;
char hostname[HOST_NAME_MAX];
char ipaddr[INET_ADDRSTRLEN];
char port[6];
serv_sock = socket(AF_INET, SOCK_STREAM, 0);
if (serv_sock == -1)
{
perror("socket");
exit(1);
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(35000);
ret = bind(serv_sock, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)); // bind socket to server address
if (ret == -1)
{
printf("bind error: %s\n", strerror(errno));
exit(1);
}
listen(serv_sock, 20);
// get hostname
gethostname(hostname, HOST_NAME_MAX);
// get ip address
getnameinfo((struct sockaddr *)&serv_addr, sizeof(serv_addr), ipaddr, INET_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
// get port number
printf("Server %s is running on %s : %s\n", hostname, ipaddr, port);
while (1)
{
data_socket = accept(serv_sock, (struct sockaddr *)&client_addr, &client_sock);
// print client host name and ip address
getnameinfo((struct sockaddr *)&client_addr, sizeof(client_addr), hostname, HOST_NAME_MAX, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
printf("Client %s is connected to %s : %s\n", hostname, ipaddr, port);
if (data_socket == -1)
{
printf("accept error: %s\n", strerror(errno));
exit(1);
}
while (1){
int n = read(data_socket, &buffer, sizeof(uint32_t));
if (n == -1)
{
printf("read error: %s\n", strerror(errno));
exit(1);
}
if (n == 0)
{
break;
}
uint32_t temp = ntohl(buffer);
printf("%d\n", temp);
}
close(data_socket);
// if (!strncmp(buffer, "418", sizeof(buffer)))
// {
// break;
// }
}
close(serv_sock);
return 0;
}
Client implimentation:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <inttypes.h>
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
int ret, data_socket, i;
unsigned int num_arr[5] = {1, 2, 3, 4, 5};
char send_str[100];
data_socket = socket(AF_INET, SOCK_STREAM, 0);
if (data_socket == -1)
{
perror("socket");
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(35000);
ret = connect(data_socket, (const struct sockaddr *)&addr, sizeof(addr));
if (ret == -1)
{
printf("connect error: %s\n", strerror(errno));
exit(1);
}
for (i = 0; i < 5; i++)
{
// sprintf(send_str, "%d\n", num_arr[i]);
// now send data as binary data
uint32_t num = htonl(num_arr[i]);
printf("%d\n", num);
printf("%d\n", ntohl(num));
write(data_socket, &num, sizeof(num));
write(data_socket, "\n", 1);
}
uint32_t delimiter = htonl(-1);
write(data_socket, &delimiter, sizeof(uint32_t));
if (argc == 2)
{
if (strncmp(argv[1], "quit", 4) == 0)
{
printf("User quits\n");
ret = write(data_socket, "418\n", 4);
}
else
{
printf("Wrong Argument\n");
}
}
close(data_socket);
return 0;
}
As the title stated - any atempts made by the serverside to send data back to the client result in an imediate crash (segmentation fault). This is a simple tcp chat app - and I am only looking to send strings bidirectionaly between client and server.
Server side below - the chat() function handles communication , after calling fgets , inputting my string , and attempting to send the data - I get an immediate (segmentation fault) and crash.
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <ifaddrs.h>
#define SA struct sockaddr
int chat(int sockfd, int port) {
for (;;) {
char *buffer_send;
char *buffer_recv;
recv(sockfd, buffer_recv, port , 0);
printf("%s", buffer_recv);
printf(":"); fgets(buffer_send, 512, stdin);
char* exit_func;
exit_func = strstr(buffer_send, "exit");
if (exit_func = strstr(buffer_send, "exit")) {
close(sockfd);
return 0;
} else {
send(sockfd, buffer_send, 512, 0);
}
}
}
int main () {
int server_socket, new_socket, c;
struct sockaddr_in socket_address, client;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
printf("socket creation failed! \n");
return 1;
} printf("socket created! \n");
socket_address.sin_addr.s_addr = inet_addr("192.168.0.10");
socket_address.sin_family = AF_INET;
socket_address.sin_port = (8003);
if( bind(server_socket,(struct sockaddr *)&socket_address , sizeof(socket_address)) < 0) {
printf("bind failed! \n");
return 1;
} printf("bind done! \n");
listen(server_socket , 3);
printf("Waiting for incoming connections...\n");
c = sizeof(struct sockaddr_in);
new_socket = accept(server_socket, (struct sockaddr *)&client, (socklen_t*)&c);
if (new_socket<0) {
printf("accept failed\n");
return 1;
} printf("connection accepted!\n");
chat(new_socket, socket_address.sin_port);
return 0;
}
however the same way of sending data on my client seems to work fine (without crashing while trying to send data):
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <ifaddrs.h>
int chat(int sockfd, int port) {
for (;;) {
char *buffer_send;
char *buffer_recv;
printf(":"); fgets(buffer_send, 512, stdin);
char* exit_func;
exit_func = strstr(buffer_send, "exit");
if (exit_func = strstr(buffer_send, "exit")) {
close(sockfd);
return 0;
} else {
send(sockfd, buffer_send, 512, 0);
}
recv(sockfd, buffer_recv, port , 0);
printf("%s", buffer_recv);
}
}
int main () {
int target_socket;
struct sockaddr_in target_server;
target_socket = socket(AF_INET, SOCK_STREAM, 0);
if (target_socket == -1) {
printf("socket creation failed!\n");
return 1;
} printf("socket created!\n");
target_server.sin_addr.s_addr = inet_addr("192.168.0.10");
target_server.sin_family = AF_INET;
target_server.sin_port = (8003);
if (connect(target_socket , (struct sockaddr *)&target_server , sizeof(target_server)) < 0) {
printf("connection failed!\n");
return 1;
} printf("connected!\n");
chat(target_socket, target_server.sin_port);
return 0;
}
You did not allocated the room for incoming messages, the same for the buffer you want to send. I expect to do some char buffer_send[512 + 1] = {}; and char buffer_recv[512 + 1] = {}; to make some place for the message content.
The + 1 is added for the extra safety, to not overwrite the NULL terminator when the message received is large enough to fill the entire allocated buffer.
I am trying to do a command line, based on socket communication.My only problem is that after exexvp is executed (and the data are being printed on the client's side), the client close and i want to keep him alive.
This is my code:
client.c
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/types.h>
#include <netdb.h>
#define PORT_NUMBER 1754
#define HOST_NUMBER
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, port_number, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3) {
//fprintf(stderr, "usage %s hostname port\n", argv[0]);
//first parameter is ip address
printf("usage %s hostname port\n", argv[0]);
exit(0);
}
port_number = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0 )
error("ERROR opening socket!Socket failed!");
printf("Trying to connect...\n");
server = gethostbyname(argv[1]); //ip address
if (server == NULL) {
error( "ERROR, no such host");
//fprintf(stderr, "ERROR, no such host\n"); exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET; //AF_UNIX
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(port_number);
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Connected!\n");
printf("%s_>\n",argv[1]);
while(1) {
printf("Please enter the message: "); //THE CLIENT MUST WRITE A COMMAND
fgets(buffer, 256, stdin); //apo stdin sto buffer
n = write(sockfd, buffer, strlen(buffer)); //apo buffer sto socket
if(n < 0 ) {
error("ERROR writing to socket");
}
bzero(buffer, 256);
if ( recv(sockfd, buffer, 256, 0) < 0) {
printf("Server closed connection\n");
}
printf("%s\n", buffer);
}
return 0;
}
sever.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
void parse(char *vector_args[20], char *buffer){
buffer[strcspn(buffer, "\n")] =0;
int i=0;
char * pch;
pch = strtok (buffer," ");
while (pch != NULL )
{
vector_args[i]=pch;
printf (" %s\n",pch);
pch = strtok (NULL, " ");
i++;
}
vector_args[i]=NULL;
int k=0;
for(k=0; k<=i; k++) {
printf("vector %d = %s \n",k,vector_args[k]);
}
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
char str[INET_ADDRSTRLEN];
char *vector_args[20];
int status;
char *fd[2];
if (argc < 2)
{
fprintf(stderr, "No port provided\n");
exit(1);
}
unlink("sockfd"); //remove any old socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
int l = listen(sockfd, 5);
if (l < 0)
{
error("listen failed!");
}
clilen = sizeof(cli_addr);
printf( "Server waiting for a connection...\n " );
while(1) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
if (inet_ntop(AF_INET, &cli_addr.sin_addr, str, INET_ADDRSTRLEN) == NULL) {
fprintf(stderr, "Could not convert byte to address\n");
exit(1);
}
fprintf(stdout, "Connected!\nThe client address is :%s\n", str);
//fork new process
int pid = fork();
if (pid == -1 ) {
error("ERROR in new process creation");
close(newsockfd);
continue;
}else if( pid != 0){
//parent process
close(newsockfd);//h edw h prin to continue
printf( " I am parent process %d\n " ,getpid()); //BGALE
if (wait(&status)== -1) /* Wait for child*/
{
perror( " wait " );
}
check_child_exit(status);
continue;
}else if (pid == 0) {
//child process
close(sockfd);
bzero(buffer, 256);
while(1) {
n = read(newsockfd, buffer, 255); //apo socket ston buffer
if (n < 0 )
error("ERROR reading from socket");
printf("Here is the message: %s\n", buffer);
n = write(newsockfd, "I got your message", 18);
bzero(buffer, 256);
close(1); //close stdin
dup2( newsockfd, 1);
close(0); //close stdout
dup2( newsockfd, 0);
parse(vector_args,buffer);
execvp(vector_args[0] , vector_args );
perror( " execvp " );
exit(EXIT_FAILURE);
bzero(buffer, 256);
}
close(newsockfd);
break;
}
}
}
Do you have any ideas how could I change my code in order to work properly?
The loop
while (1) {
....
execvp(....);
}
is effectively executed once. The reason is that the successful execvp replaces the code with whatever vector_args requests, and the executed process just exits when done.
If I understand your goals correctly (one process per connection, executing external commands in the loop), you need one more fork, along the lines of
while (1) {
....
if ((pid = fork()) == 0) {
execvp(....);
} else if (pid > 0) {
waitpid(....);
} else {
handle_error();
}
}
If client send pwd, server may recv p w d or pw d or pwd and so on.
In my opinion, if client want to send pwd, client should send pwd\n, server will read command until \n. If server want to send 123, server should send 123\0, client will read until \0. I write a tiny example, you could learn from it. The server code will continue until client quit.
server.c
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
void parse(char** argv, char* buffer) {
int i = 0;
argv[i] = strtok(buffer, " ");
while (argv[i] != NULL) argv[++i] = strtok(NULL, " ");
}
void handle_client(int con_socket) {
for (;;) {
char buf[1024];
ssize_t i = 0;
for (;;) {
ssize_t ret = read(con_socket, buf + i, 1);
if (ret == 0) return;
if (buf[i] == '\n') {
buf[i] = '\0';
break;
}
++i;
}
int pipe_fd[2];
pipe(pipe_fd);
if (fork() == 0) {
close(con_socket);
dup2(pipe_fd[1], 1);
close(pipe_fd[0]);
close(pipe_fd[1]);
char* argv[25];
parse(argv, buf);
execvp(argv[0], argv);
exit(EXIT_FAILURE);
} else {
close(pipe_fd[1]);
for (;;) {
ssize_t ret = read(pipe_fd[0], buf, sizeof(buf));
if (ret == 0) {
write(con_socket, "", 1);
break;
}
write(con_socket, buf, ret);
}
wait(NULL);
}
}
}
int main() {
const char* server_ip = "127.0.0.1";
uint16_t server_port = 6666;
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof server_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
inet_pton(AF_INET, server_ip, &server_addr.sin_addr);
int listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int opt = 1;
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bind(listen_socket, (struct sockaddr*)(&server_addr),
(socklen_t)(sizeof server_addr));
listen(listen_socket, 5);
for (;;) {
int con_socket = accept(listen_socket, NULL, NULL);
if (fork() > 0) {
close(con_socket);
wait(NULL);
continue;
} else {
close(listen_socket);
handle_client(con_socket);
close(con_socket);
break;
}
}
return 0;
}
client.c
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
const char* server_ip = "127.0.0.1";
uint16_t server_port = 6666;
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof server_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
inet_pton(AF_INET, server_ip, &server_addr.sin_addr);
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
for (;;) {
printf(">> ");
char buffer[256];
fgets(buffer, 256, stdin);
if (strlen(buffer) == 0) continue;
write(sockfd, buffer, strlen(buffer));
for (;;) {
ssize_t ret = recv(sockfd, buffer, 256, 0);
buffer[ret] = '\0';
printf("%s", buffer);
if (buffer[ret - 1] == '\0') break;
}
}
return 0;
}
Modify the following socket program and let the server send a file to the client.
I'm stuck with this i can't figure this out.
below is the server and client that where given to me. right now the server will send the client the time stamp.
Socket Server Example (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 = 0, connfd = 0;
struct sockaddr_in serv_addr;
char sendBuff[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);
ticks = time(NULL);
snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n",
ctime(&ticks));
write(connfd, sendBuff, strlen(sendBuff));
close(connfd);
sleep(1);
}
}
Socket Client Example (client.c)
#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 = 0, n = 0;
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");
}
return 0;
}
If you don't want to or can't read the whole content of the file you wish to send at once into memory, use a loop with your buffer:
#include <fcntl.h>
if (argv[1]) // or whereever you get the file name from
{
int fd = open(argv[1], O_RDONLY);
if (fd < 0) perror(argv[1]);
else
{
ssize_t n;
while (n = read(fd, sendBuff, sizeof sendBuff), n > 0)
if (send(connfd, sendBuff, n, MSG_NOSIGNAL) < 0)
{ perror("send"); break; }
close(fd);
if (n < 0) perror("read");
}
}
In the client use a similar loop. Be aware that the file might contain NUL characters, so functions like fputs, operating on C strings, are inept.
while ((n = read(sockfd, recvBuff, sizeof recvBuff)) > 0)
if (write(1, recvBuff, n) < 0) perror("write");
Read the content of the file you wish to send, and save it into a string:
char *loadFileContent(char *fileName, size_t *len){
FILE* input_file = fopen(fileName, "rb");
size_t stat;
if(!input_file){
OCSP_ERR_INDEX = OCSP_LOG_ERR_load_file_fail;
return NULL;
}
fseek(input_file, 0, SEEK_END);
long int input_file_size = ftell(input_file);
rewind(input_file);
char *file_contents = malloc((input_file_size + 1) * (sizeof(char)));
stat = fread(file_contents, sizeof(char), (size_t) input_file_size, input_file);
if(stat<1){
OCSP_ERR_INDEX = OCSP_LOG_ERR_load_file_fail;
return NULL;
}
fclose(input_file);
file_contents[input_file_size] = 0;
*len = (size_t) input_file_size;
return file_contents;
}
In your code, modify the line in server that is supposed to send response to client.
So this line write(connfd, sendBuff, strlen(sendBuff)); becomes:
size_t len;
char *text = loadFileContent("myfile.txt", &len);
write(connfd, text, len);
I have socket code and client code below. So far all that it does is establish connection with the server, but I want it to also send a file from the client to the server; even if the file has no data in it. What do I have to do to augment this code to send files? Any suggestions in code form?
Client:
#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 = 0, n = 0;
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");
}
return 0;
}
Server:
#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 = 0, connfd = 0;
struct sockaddr_in serv_addr;
char sendBuff[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);
ticks = time(NULL);
snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
write(connfd, sendBuff, strlen(sendBuff));
close(connfd);
sleep(1);
}
}
I havn't tried compiling this, and this code is certainly not polished but something similar to below will do the trick :)
Modify the client end to look like this:
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
FILE *inputFile = fopen("inputFile.txt", "rb");
if(inputFile == NULL)
{
fprintf(stderr, "oh no!");
return 1;
}
char sendBuffer[10];
// TODO: Check for errors here
int bytesRead = fread(sendBuffer, sizeof(sendBuffer), 1, inputFile);
while(!feof(inputFile))
{
//TODO: check for errors here
send(sockfd, sendBuffer, bytesRead, 0);
bytesRead = fread(sendBuffer, sizeof(sendBuffer), 1, inputFile);
}
close(sockfd);
Modify the server end to look like this:
listen(listenfd, 10);
FILE *outputFile = fopen("output.txt", "wb");
if(outputFile == null)
{
fprintf(stderr, "Something went south!");
return 1;
}
while(1)
{
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
char recvBuff[10];
ticks = time(NULL);
int bytesReceived = recv(confd, recvBuff, 10, 0);
while(bytesReceived != 0)
{
// you should add error checking here
fwrite(recvBuff, bytesReceived, 1, outputFile);
bytesReceived = recv(confd, recvBuff, 10, 0);
}
close(connfd);
}