Sever fails to exit accept loop once client is done delivering message - c

Created client program using fork to read multiple files and create separate sockets. Then each socket sends the message in the file it read to the server, which uses fork to handle multiple clients. However, the sever never exits the accept loop - hence it never terminates even after all sockets on the client side are closed.
server:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include "uthash.h" //Used for building hash map
#define PORT "3400"
#define HOST "localhost"
#define MAXDATASIZE 20
#define DEPARTMENT_LEN 2
#define BACKLOG 5
int main(void){
int sockfd, rv, child, numBytes;
int opt = 1;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; //connector's address information
socklen_t sin_size;
struct sigaction sa;
char dept[MAXDATASIZE];
double gpa;
char dept_name[DEPARTMENT_LEN + 1];
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if((rv = getaddrinfo(HOST, PORT, &hints, &servinfo)) != 0){
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
//loop though all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next){
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
perror("server: socket");
continue; //move to next available socket
}
//reuse port and supress address already in use warnings
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) == -1){
perror("server: setsockopt");
exit(1);
}
//Bind socket and local address
if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
close(sockfd);
perror("server: bind");
continue;
}
break;
}
if(p == NULL){
fprintf(stderr, "server: failed to bind\n");
return 1;
}
freeaddrinfo(servinfo); //free list structure
//Listen to client
if(listen(sockfd, BACKLOG) == -1){
perror("server: listen");
exit(1);
}
//Reap all dead processes
sa.sa_handler = sigchild_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if(sigaction(SIGCHLD, &sa, NULL) == -1){
perror("sigaction");
exit(1);
}
while(1){//accept() main loop
sin_size = sizeof(their_addr);
if((child = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1){
perror("server: accept");
continue;
}
if(!fork()){//this is the child process
close(sockfd);
while(1){
if((numBytes = recv(child, dept, MAXDATASIZE, 0)) == -1){
perror("server: recv");
exit(1);
}
dept[numBytes] = '\0';
if(strcmp(dept, ":exit") == 0){
printf("%s\n", dept);
break;
}
else{
//printf("%s\n", dept);
_parse_dept(dept, dept_name, &gpa);
//printf("%s: %.1f\n", dept_name, gpa);
_add_dept(dept_name, gpa);
// _print_dept();
bzero(dept_name, (int)strlen(dept_name));
bzero(dept, (int)strlen(dept));
}
}//end while
//_print_dept();
printf("%d\n", 2);
close(child);
exit(0);
}// end fork
printf("%d\n", 3);
close(child); //parent doesn't need this
}
printf("%d\n", 4);
//_print_dept();
// _delete_all();
return 0;
}
client:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#define PORT "3400"
#define NO_DEPARTMENTS 3
#define LINE_SIZE 7
#define HOST "localhost"
//Global variable containing respective departments file name extensions
char * filenames[] = {"DepartmentA.txt", "DepartmentB.txt", "DepartmentC.txt"};
char * department_names[] = {"DepartmentA", "DepartmentB", "DepartmentC"};
int main(void){
pid_t child_pid, wpid;
int status = 0;
for(int ii = 0; ii < NO_DEPARTMENTS; ii++){
if((child_pid = fork()) == 0){
int sockfd, rv;
char dept_ip[INET6_ADDRSTRLEN]; //Department IP address
unsigned int dept_port; //Department port
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in my_addr;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if((rv = getaddrinfo(HOST, PORT, &hints, &servinfo)) != 0){
fprintf(stderr, "\ngetaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
//loop through all the results and connect to the first that we can find
for(p = servinfo; p != NULL; p = p->ai_next){
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
close(sockfd);
perror("client: socket");
continue;
}
if(connect(sockfd, p->ai_addr, p->ai_addrlen) == -1){
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if(p == NULL){
fprintf(stderr, "client: failed to connect\n");
return 1;
}
//1) Upon startup of Phase 1
socklen_t len = sizeof(my_addr);
getsockname(sockfd, (struct sockaddr *)&my_addr, &len);
inet_ntop(AF_INET, &my_addr.sin_addr, dept_ip, sizeof(dept_ip));
dept_port = ntohs(my_addr.sin_port);
printf("<%s> has TCP port %d ", filenames[ii], dept_port);
printf("and IP address %s for Phase 1\n", dept_ip);
//2) Upon establishing a TCP connection to the admission office
printf("<%s> is now connected to the admission office\n", filenames[ii]);
//readfile and send contents to Addmissions office
struct Node * fileContent = NULL;
_readFile(&fileContent, filenames[ii]);
struct Node * fileIter = fileContent;
while(fileIter != NULL){
sleep(3);
send(sockfd, fileIter->dept, (int)strlen(fileIter->dept), 0);
fileIter = fileIter->next;
}
sleep(3);
char *ex = ":exit";
send(sockfd, ex, (int)strlen(ex), 0);
_freeFile(&fileContent);
freeaddrinfo(servinfo); // free up list structure
close(sockfd);
exit(0); //exit for fork
}
}
while ((wpid = wait(&status)) > 0);
return 0;
}

Solved It! I had to make the queue (BACKLOG) for the accept the same amount as the number of departments, which is 3 in in this case. Then I initialized a counter to the size of the queue and decremented it each time an accept was performed. Once the counter hit zero I had the parent process wait for all the children and then break the accept loop manually.
if(counter > 0){
close(child); //parent doesn't need this
continue;
}else{
wait(&status);
printf("End of Phase 1 for the admission office\n");
break;
}

Related

How can I connect to the server?

I've just started taking network programming classes and this is what we did in class in order to make connection between client and server. My problem is that I cannot connect to the server, it just stops after printing "addrinfo is successful" and does not loop through.
We used 8080 for port number in class and that did not work, so I tried using 7070 and it worked maybe 1 out of 50 times. I don't have any problems with the client side of the program, it works completely fine. I'm using Visual Studio Code on MacBook if that makes any difference, I also tried using the terminal but that did not work either.
//client to server
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
int main(){
const char *hostname = "127.0.0.1";
const char *portNumber = "7070";
int clientSocket; //socketFD
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
struct addrinfo *results; // const for head
struct addrinfo *record; // temp for traversing
int error;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(hostname, portNumber, &hints, &results);
// error checking
if(error >= 0){
printf("Client: getaddressinfo() successful\n ");
}
//traversing the list
for(record = results; record != NULL; record = record->ai_next){
clientSocket = socket(record->ai_family, record->ai_socktype, 0);
if(clientSocket == -1){
continue;
}
if(connect(clientSocket, record->ai_addr, record-> ai_addrlen) != -1){
break;
}
close(clientSocket);
}
//socket() and connect() both were success
//send()
if(record == NULL){
printf("Error\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(results);
printf("socket status: created and connected\n");
char *message = "Hello" ;
if(send(clientSocket, message, strlen(message), 0) == -1){
printf("Error\n");
exit(EXIT_FAILURE);
}
else{
printf("Message sent successfuly\n");
}
close(clientSocket);
return 0;
}
//server
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
int main(){
printf("Starting the server\n");
const size_t bufferSize = 1024;
const char *portNumber = "7070";
const int backlog = 1;
int serverSocket;
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo *results;
struct addrinfo *record;
if((getaddrinfo(NULL, portNumber, &hints, &results)) != 0){
printf("Error\n");
exit(EXIT_FAILURE);
}
printf("addrinfo is successful\n");
//traverse through the list
for(record = results; record != NULL; record = record->ai_next){
serverSocket = socket(record->ai_family, record->ai_socktype, record->ai_protocol);
if(serverSocket == -1){
continue;
}
int enable = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
if(bind(serverSocket, record->ai_addr, record->ai_addrlen) == 0){
break;
}
close(serverSocket);
}
if(record == NULL){
exit(EXIT_FAILURE);
}
freeaddrinfo(results);
printf("Socket status: created and binded successfuly\n");
if(listen(serverSocket, backlog) == -1){
printf("ERROR\n");
exit(EXIT_FAILURE);
}
printf("Server is listening\n");
while(1){
int clientSocket;
struct sockaddr clientAddress;
socklen_t clientAddressLength = sizeof(clientAddress);
if((clientSocket = accept(serverSocket, &clientAddress, &clientAddressLength)) <0){
printf("Error\n");
exit(EXIT_FAILURE);
}
printf("Client socket accepted\n");
char buffer[bufferSize];
if(recv(clientSocket, buffer, sizeof(buffer), 0) == -1){
printf("Error\n");
exit(EXIT_FAILURE);
}
printf("Message is received: %s\n", buffer);
close(clientSocket);
printf("Client socket is closed\n");
}
return 0;
}

TCP client/server in c

I created a TCP client/server and was provided test script, however, beyond short messages, all tests are failing. Simply, the script send arbitrary messages that the client reads through redirection from a file to ther server. However with randomly created files by the script, it says that the messages on receving/sending side do not match. Any help will be appreciated, below is the client and server code.
// server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#define QUEUE_LENGTH 10
#define RECV_BUFFER_SIZE 2048
/* TODO: server()
* Open socket and wait for client to connect
* Print received message to stdout
* Return 0 on success, non-zero on failure
*/
int server(char *server_port) {
int sockfd, new_fd;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address
socklen_t sin_size;
int yes = 1;
char s[INET6_ADDRSTRLEN];
int rv;
char buff[RECV_BUFFER_SIZE];
int numBytes;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my ip address
if ((rv = getaddrinfo(NULL, server_port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(servinfo); // all done with this structure
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
if (listen(sockfd, QUEUE_LENGTH) == -1) {
perror("listen");
exit(1);
}
// printf("server: waiting for connections...\n");
while (1) {
sin_size = sizeof their_addr;
if((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
perror("accept");
continue;
}
if (!fork()) { // child process
close(sockfd); // child does not need the listener
if ((numBytes = recv(new_fd, buff, RECV_BUFFER_SIZE -1, 0)) == -1) {
perror("recv");
exit(1);
}
buff[numBytes] = '\0';
printf("%s", buff);
close(new_fd);
exit(0);
}
close(new_fd);
}
return 0;
}
/*
* main():
* Parse command-line arguments and call server function
*/
int main(int argc, char **argv) {
char *server_port;
if (argc != 2) {
fprintf(stderr, "Usage: ./server-c [server port]\n");
exit(EXIT_FAILURE);
}
server_port = argv[1];
return server(server_port);
}
// client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#define SEND_BUFFER_SIZE 2048
/* TODO: client()
* Open socket and send message from stdin.
* Return 0 on success, non-zero on failure
*/
int client(char *server_ip, char *server_port)
{
int sockfd;
int status;
struct addrinfo hints, *servinfo, *p;
char send_buff[SEND_BUFFER_SIZE];
int numbytes;
char s[INET6_ADDRSTRLEN];
// getaddrinfo
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((status = getaddrinfo(server_ip, server_port, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getadrrinfo: %s\n", gai_strerror(status));
return 1;
}
for (p = servinfo; p != NULL; p = p->ai_next)
{
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1)
{
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("client: socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
return 2;
}
freeaddrinfo(servinfo);
// reading from stdin into send_buff, then send
if((numbytes = read(0, send_buff, SEND_BUFFER_SIZE)) != -1) {
if (send(sockfd, send_buff, numbytes, 0) == -1) {
perror("send");
exit(1);
}
}
close(sockfd);
return 0;
}
/*
* main()
* Parse command-line arguments and call client function
*/
int main(int argc, char **argv)
{
char *server_ip;
char *server_port;
if (argc != 3)
{
fprintf(stderr, "Usage: ./client-c [server IP] [server port] < [message]\n");
exit(EXIT_FAILURE);
}
server_ip = argv[1];
server_port = argv[2];
return client(server_ip, server_port);
}
2048 bytes exceed in size the typical MTU (note that TCP is laid over IP, which itself is packet oriented), so data is likely sent via multiple packets. As you have only one single call to recv chances are that you fetch the contents of first packet from the receive buffer before the the TCP/IP stack could place the contents of the follow up packets there.
Rather have multiple reads in a loop and exit the loop on receiving 0 bytes (remote socket closed):
while((numBytes = recv(new_fd, buff, RECV_BUFFER_SIZE -1, 0)) > 0)
{
buff[numBytes] = '\0';
printf("%s", buff);
}
if(numBytes < 0)
{
// error handling
}

Unbinding ports

I launched a process from terminal that bound some ports.
The code in questions is this one:
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#define BUF_SIZE 500
#define LISTEN_BACKLOG 50
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
struct addrinfo hints;
struct addrinfo *res, *rp;
struct sockaddr_storage peer_addr;
socklen_t peer_addr_len;
int sfd, cfd;
if(argc != 3) {
fprintf(stderr, "Usage: %s address port\n", argv[0]);
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_addr = NULL;
hints.ai_next = NULL;
if(getaddrinfo(argv[1], argv[2], &hints, &res) != 0)
handle_error("getaddrinfo");
// Try each socket until we bind
for(rp = res; rp != NULL; rp = rp->ai_next){
sfd = socket(rp->ai_family, rp->ai_socktype, 0);
if(sfd == -1) continue;
if(bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) break;
else close(sfd);
}
freeaddrinfo(res);
if (rp == NULL){
fprintf(stderr, "Could not bind to any socket\n");
exit(EXIT_FAILURE);
}
// Set the TCP socket to listen state
if (listen(sfd, LISTEN_BACKLOG) == -1) handle_error("listen");
printf("Server started");
for(;;){
// Accept
peer_addr_len = sizeof(struct sockaddr_storage);
cfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_len);
if (cfd == -1) handle_error("accept");
// Fork
pid_t pid = fork();
if (pid == 0){ //Child code
pid_t my_pid = getpid();
char buf[BUF_SIZE];
while(1){
ssize_t nread = recv(cfd, buf, BUF_SIZE, 0);
if (nread == 0) {
close(cfd);
exit(EXIT_SUCCESS);
} else {
buf[nread] = 0;
fprintf(stdout, "Worker %i has received a message: %s", my_pid, buf);
ssize_t nsent = send(cfd, buf, nread, 0);
if (nsent != nread) fprintf(stderr, "Error sending response");
}
}
}
close(sfd);
}
After invoking the code I killed the process, and noticed that I could not run the program twice using the same port.
I checked sudo lsof -i -P -n | grep LISTEN and it listed the ports I had used for testing as being in LISTEN state and my program being the culprit for that.
How can I unbind the ports? How do I modify my code so it unbinds the ports itself after receiving a suitable signal?

Random function working on Linux not on Mac

I'm currently learning network programming in university and programmed a server. As we need this one for further progress I need to reuse the code every time. There is a random function with an error I don't really get because on the linux pcs at university everything compiles well only my mac which I do all my homework shows this error.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
//#define PORT "3490" // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
int random(int min, int max){
srand ( time(NULL) );
return min + rand() / (RAND_MAX / (max - min + 1) + 1);
}
void sigchld_handler(int s)
{
// waitpid() might overwrite errno, so we save and restore it:
int saved_errno = errno;
while(waitpid(-1, NULL, WNOHANG) > 0);
errno = saved_errno;
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[])
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
//int linetoread;
if (argc != 3) {
fprintf(stderr,"usage: server port txtfile\n");
exit(1);
}
FILE* fp;
char buffer[255];
int i = 0;
char rnd[200][255];
int fixed;
fp = fopen(argv[2], "r");
while(fgets(buffer, 255, (FILE*) fp)) {
//printf("%s\n", buffer);
for (int j = 0; j < 255; j++){
rnd[i][j] = buffer[j];
}
i++;
}
fclose(fp);
//printf("number of lines: %d\n", i);
//linetoread = rand() % i;
//printf("%d\n", random(0,i));
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, argv[1], &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(servinfo); // all done with this structure
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
fixed = random(0,i-1);
//printf("line: %d\n", fixed);
if (send(new_fd, rnd[fixed], strlen(rnd[fixed]), 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
return 0;
}
Error on my mac:
server.c:16:5: error: conflicting types for 'random'
int random(int min, int max){
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/stdlib.h:233:7: note:
previous declaration is here
long random(void) __swift_unavailable("Use arc4random instead.");
^
server.c:132:19: error: too many arguments to function call, expected 0, have 2
fixed = random(0,i-1);
~~~~~~ ^~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/stdlib.h:233:1: note:
'random' declared here
long random(void) __swift_unavailable("Use arc4random instead.");
^
2 errors generated.
random() is a known function name. change it to something else and it will work.

Keep socket open in C

I think this may be a simple solution I'm just over thinking. I'm writing an extremely basic chat program where the client and server takes turns sending a message. Right now I have it where it sends a message back and forth only once and the client closes the socket. The program doesn't have to have sockets open simultaneously, just as long as it can switch back and forth like a swing, rather than a real chat program where the it can take multiple inputs from both sides all at once.
Will a while loop in the client keep it open and what are the conditions of the while loop?
I've tried several different conditions and none of them worked... it just makes it hang. I've also tried commenting out some of the close() functions in the server code, but that didn't work either.
I also have a small issue of the received input printing gibberish, but I think it's because it's printing the memory addresses of the string array when there's nothing in it... I just can't remember how to shorten it. Lol.
Server.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define PORT "3490" // The port users will be connecting to
#define BACKLOG 10 // How many pending connections queue will hold
char input[20];
char *pointer;
void sigchld_handler(int s)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
// Get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
int sockfd, new_fd; // Listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // Connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes = 1;
char s[INET6_ADDRSTRLEN];
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
return 2;
}
freeaddrinfo(servinfo); // All done with this structure
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // Reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
sin_size = sizeof their_addr;
while((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) > 0) { // Main accept() loop
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
char input[20];
char *pointer;
printf("Type in an server's input: ");
scanf("%s", input);
pointer = input; //Will need to clean this up to be more effcient... later
if (send(new_fd, pointer, strlen(input), 0) == -1) //Need to change the length to
//the actual length of the
//input... later.
perror("send");
close(new_fd);
exit(0);
}
char Cinput[20];
if ((recv(new_fd, Cinput, strlen(Cinput), 0)) == 0) { //NEW LINE ADDED HERE
printf("No more messages");
}
if ((recv(new_fd, Cinput, strlen(Cinput), 0)) == -1) {
perror("recv");
exit(1);
}
printf("Server: received '%s'\n",Cinput);
close(new_fd); // Parent doesn't need this
}
return 0;
}
Client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define PORT "3490" // The port client will be connecting to
#define MAXDATASIZE 100 // Max number of bytes we can get at once
// Get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[])
{
int sockfd, numbytes;
char buf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
/*
This is what is in the struct
struct addrinfo {
int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc.
int ai_family; // AF_INET, AF_INET6, AF_UNSPEC
int ai_socktype; // SOCK_STREAM, SOCK_DGRAM
int ai_protocol; // Use 0 for "any"
size_t ai_addrlen; // Size of ai_addr in bytes
struct sockaddr *ai_addr; // struct sockaddr_in or _in6
char *ai_canonname; // Full canonical hostname
struct addrinfo *ai_next; // Linked list, next node
};
getaddrinfo() will return a pointer to this
*/
int rv;
char s[INET6_ADDRSTRLEN];
if (argc != 2) {
fprintf(stderr,"usage: client hostname\n");
exit(1);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// Loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
return 2;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("client: connecting to %s\n", s);
freeaddrinfo(servinfo); // All done with this structure
while(1)//NEW LINE ADDEDthis is getting the client to repeat asking for the input, but doesn't send it.
{
if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == 0) { //NEW LINE ADDED
printf("Shutdown");
}
if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
printf("client: received '%s'\n",buf);
char Cinput[20];
char *pointer;
printf("Type in an client's input: ");
scanf("%s", Cinput);
pointer = Cinput;
if (send(sockfd, pointer, strlen(Cinput), 0) == -1)
{
perror("send");
close(sockfd);
exit(0);
}
}
close(sockfd); //As soon as the client receives a message, it closes the socket.
//We probably need a while loop in here in order to keep the socket open,
//but what are the parameters for the while loop?
return 0;
}
The following pseudocode will ensure that the same client and server can infinitely send messages to each other until one of them hangs up:
Client:
Create the socket.
connect to it.
recv data.
If recv returns 0, it means the other end has performed an orderly shutdown. Go to step 7.
send response.
Go to step 3.
Stop.
Server:
Create the socket.
bind the socket to an address.
Mark the socket as listening.
accept a connection.
If accepted connection is invalid, go to step 4.
send data.
recv response.
If recv returns 0, it means the other end has performed an orderly shutdown. Go to step 4 to accept a new connection.
Go to step 6.

Resources