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.
Related
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
}
So i have a client.c file on a computer in my lan and a server.c file on another computer. Essentially i start the server.c file and specify what port it needs to listen to as it waits. I think run my client.c command by specifying the address were server.c is running and what port to send my command on. the only thing my client sends is a filename (call it test.txt). My server is then to take that command using recv() from the C socket protocols, and i would like to be able to read that file and send that output back to my client so that it outputs to my clients terminal. I have figured out how to send the file as that is easy but i am having a hard time understanding how I can do this task with sockets. Do i just need to issue a write command using send() ? Do i need to read the file and send line by line to the socket ? if thats the case and say i have 10 clients do i need to use a semaphore or mutex to make sure that the output is sent fully before moving on to the next client request?
The code does more than just what I am asking for it also has a logging feature. and i have been using
http://beej.us/guide/bgnet/html/ as a guide. But its just sending back the contents of the file that is on the server.c machine to the client.c output that is kinda causing me to go in circles.
so in theory it should look something like this on the client side
./client 129.65.128.82:4443 bigfile
...entire contents of bigfile should appear here...
Here is my Server.c Code and Client.c (at the bottom for reference)
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>
#include <time.h>
#include <sys/stat.h>
#define PORT "4443" // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
size_t getFilesize(const char* filename) {
struct stat st;
if(stat(filename, &st) != 0) {
return 0;
}
return st.st_size;
}
void fileOutput(char *filename){
FILE *fptr;
char c;
//int check = checkFilename(filename);
fptr = fopen(filename,"r");
printf("We opened the file\n");
if (fptr == NULL)
{
printf("Cannot open file \n");
exit(0);
}
printf("HereWe ARE\n");
// Read contents from file
c = fgetc(fptr);
while (c != EOF)
{
printf ("%c", c);
c = fgetc(fptr);
}
fclose(fptr);
}
void sigchld_handler(int s)
{
(void)s; // quiet unused variable warning
// waitpid() might overwrite errno, so we save and restore it:
int saved_errno = errno;
while ( waitpid(-1, NULL, WNOHANG) > 0 );
errno = saved_errno;
}
void argumentCheck(int n){
if (n < 2) {
fprintf(stderr,"Usage: server port # example port 4443\n");
exit(1);
}
}
// 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);
}
void logfile(FILE *fp,char *s,char *port,char *buffer,int r){
time_t t = time((time_t*) NULL);
struct tm *tm = localtime(&t);
char tc[256];
strftime(tc, 256, "%Y-%m-%d %H:%M:%S", tm);
fprintf(fp,"[%s] %s:%s %s %d\n",tc,s,port,buffer,r);
}
int main(int argc, char **argv)
{
//Log file creation
FILE *fp;
fp = fopen("log","a");
///////
///File Size///
//////////////
argumentCheck(argc);
int sockfd, new_fd; // listen on sockfd, 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;
char *inputPort = argv[1];
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, inputPort, &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);
}
// listen allows queue of up to BACKLOG number
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
char buf[1024];
close(sockfd); // child doesn't need the listener
printf("this is the sizeof buf %ld\n",sizeof(buf));
recv(new_fd,buf, sizeof(buf),0);
int size = getFilesize(buf);
logfile(fp,s,inputPort,buf,size);
fileOutput(buf);
if ( send(new_fd, buf, size, 0) == -1)
perror("send");
printf("%s\n",buf);
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
fclose(fp);
return 0;
}
Client.c code:
#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 "4443" // the port client will be connecting to
// 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)
{
if ( argc < 2 ) {
fprintf(stderr,"Usage: client ipaddr:port # example 129.65.128.82:4443 [filename]\n");
exit(1);
}
int sockfd, numbytes;
char buf[BUFSIZ];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET_ADDRSTRLEN];
// Used to extract ipv4 and socket seperatly
char *ip_address = strtok(argv[1],":");
char *ip_port = strtok(NULL,":");
memset(&hints, 0, sizeof(hints)); // make sure the struct is empty
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ( (rv = getaddrinfo(ip_address, ip_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 ) {
perror("client: connect");
close(sockfd);
continue;
}
break;
}
if ( p == NULL ) {
fprintf(stderr, "client: failed to connect\n");
return 2;
}
//printf("we are stopping here");
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
//strcpy(buf, "Hello World.\n");
//printf("this is argv2 size %ld\n",strlen(argv[2]));
strcpy(buf,argv[2]);
//printf("this is buf size %ld\n",strlen(buf));
//write(1, "client send: ", strlen("client send: "));
//write(1, buf, strlen(buf));
send(sockfd, buf, sizeof(buf), 0);
if ( (numbytes = recv(sockfd, buf, sizeof(buf)-1, 0)) == -1 ) {
printf("this is numbytes %d\n",numbytes);
perror("recv");
exit(1);
}
printf("this is numbytes %d\n",numbytes);
buf[numbytes] = '\0';
//write(1, "client recv: ", strlen("client recv: "));
//write(1, buf, strlen(buf));
close(sockfd);
return 0;
}
enter code here
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;
}
I'm facing a problem with sockets programming in C.
I've coded a server where multiple clients can connect and send messages in a chatroom but i don't know how to connect two clients two by two.
example:
Client A connect to the Server but must wait in a queue waiting for Client B to connect.
Client C connect but must wait in a queue waiting for Client D to connect.
Every pair of clients must be in their specific chatroom, do I need to share the fd between the two sockets of the 2 clients or link between the two sockets.
I thought about using another way by using the function accept() twice before I fork() but I have to use child processes for that.
Here is my server code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT "8888"
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)
{
fd_set master;
fd_set read_fds;
int fdmax;
int listener;
int newfd;
struct sockaddr_storage remoteaddr;
socklen_t addrlen;
char buf[256];
int nbytes;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1;
int i, j, rv;
struct addrinfo hints, *ai, *p;
FD_ZERO(&master);
FD_ZERO(&read_fds);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "Server msg: %s\n", gai_strerror(rv));
exit(1);
}
for(p = ai; p != NULL; p = p->ai_next)
{
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) {
continue;
}
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "Server msg: bind failed\n");
exit(2);
}
freeaddrinfo(ai);
puts("Bind success");
if (listen(listener, 10) == -1)
{
perror("listen");
exit(3);
}
puts("Server listening ...");
FD_SET(listener, &master);
fdmax = listener;
for(;;)
{
read_fds = master;
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select");
exit(4);
}
for(i = 0; i <= fdmax; i++)
{
if (FD_ISSET(i, &read_fds))
{
if (i == listener)
{
addrlen = sizeof remoteaddr;
newfd = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);
if (newfd == -1)
{
perror("accept");
}
else
{
FD_SET(newfd, &master);
if (newfd > fdmax)
{
fdmax = newfd;
}
printf("Server msg: new connection from %s on "
"socket %d\n", inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN), newfd);
}
}
else
{
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0)
{
if (nbytes == 0)
{
printf("Server msg: socket %d lost\n", i);
}
else
{
perror("recv");
}
close(i);
FD_CLR(i, &master);
}
else
{
for(j = 0; j <= fdmax; j++)
{
if (FD_ISSET(j, &master))
{
if (j != listener && j != i)
{
if (send(j, buf, nbytes, 0) == -1)
{
perror("send");
}
}
}
}
}
}
}
}
}
return 0;
}
And here is my client code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <arpa/inet.h>
#define PORT "8888"
#define MAXDATASIZE 100
#define MAXNAMESIZE 25
void *receive_handler(void *);
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[])
{
char message[MAXDATASIZE];
char nickName[MAXNAMESIZE];
int sockfd;
char sBuf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
if (argc != 2) {
fprintf(stderr,"Usage: ./client address\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;
}
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: connection failed\n");
return 2;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("Client: connection to %s\n", s);
freeaddrinfo(servinfo);
puts("Give your username:");
memset(&nickName, sizeof(nickName), 0);
memset(&message, sizeof(message), 0);
fgets(nickName, MAXNAMESIZE, stdin);
pthread_t recv_thread;
if( pthread_create(&recv_thread, NULL, receive_handler, (void*)(intptr_t) sockfd) < 0)
{
perror("Failed on thread creation");
return 1;
}
puts("Connection established");
puts("Welcome!\n");
puts("[Type '/quit' to quit the chatroom]");
for(;;)
{
char temp[6];
memset(&temp, sizeof(temp), 0);
memset(&sBuf, sizeof(sBuf), 0);
fgets(sBuf, 100, stdin);
if(sBuf[0] == '/' &&
sBuf[1] == 'q' &&
sBuf[2] == 'u' &&
sBuf[3] == 'i' &&
sBuf[4] == 't')
return 1;
int count = 0;
while(count < strlen(nickName))
{
message[count] = nickName[count];
count++;
}
count--;
message[count] = ':';
count++;
for(int i = 0; i < strlen(sBuf); i++)
{
message[count] = sBuf[i];
count++;
}
message[count] = '\0';
if(send(sockfd, message, strlen(message), 0) < 0)
{
puts("Sent failed");
return 1;
}
memset(&sBuf, sizeof(sBuf), 0);
}
pthread_join(recv_thread , NULL);
close(sockfd);
return 0;
}
void *receive_handler(void *sock_fd)
{
int sFd = (intptr_t) sock_fd;
char buffer[MAXDATASIZE];
int nBytes;
for(;;)
{
if ((nBytes = recv(sFd, buffer, MAXDATASIZE-1, 0)) == -1)
{
perror("recv");
exit(1);
}
else
buffer[nBytes] = '\0';
printf("%s", buffer);
}
}
Yes, in my opinion you can use two accept and then call a fork() or, even better, a new thread. You can create a new process/thread for each pair of connections.
What do you mean sharing the fd? You mean sending a fd of one client to another? In this case NO
You can keep, in the thread function, a mapping between the two clients to know which clients are paired. When receiving a message from one client, thanks to the mapping, you know which client you are supposed to send the message to.
I think the rest depends on further details you should specify in your question.
Let me know
If each client can both send and receive you might want to use multithreading on client-side too: one to send and one to receive.
I am attempting to write a simple chat program where one user can connect to a host. The two should be able to talk to each other (they might interrupt each other but that is ok). I am having difficulties with select(). Here is the code:
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 MAXDATASIZE 1024 // 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];
char buffer[1024];
char *buff;
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
char *port;
int num;
struct timeval tv;
//select data
fd_set rfds;
fd_set wfds;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
if (argc != 2) {
fprintf(stderr, "usage: client port\n");
exit(1);
}
port = argv[1];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo("localhost", 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
FD_SET(sockfd, &rfds);
FD_SET(sockfd, &wfds);
if (select(sockfd + 1, &rfds, &wfds, NULL, &tv) < 0) {
perror("select");
return -1;
}
if (FD_ISSET(sockfd, &wfds)) {
while (1) {
fgets(buffer, MAXDATASIZE - 1, stdin);
if ((send(sockfd, buffer, strlen(buffer), 0)) == -1) {
fprintf(stderr, "Failure Sending Message\n");
close(sockfd);
exit(1);
} else {
printf("Message being sent: %s\n", buffer);
break;
}
}
}
if (FD_ISSET(sockfd, &rfds)) {
while (1) {
if ((num = recv(sockfd, buffer, 10240, 0)) == -1) {
//fprintf(stderr,"Error in receiving message!!\n");
perror("recv");
exit(1);
} else if (num == 0) {
printf("Connection closed\n");
return 0;
}
// num = recv(client_fd, buffer, sizeof(buffer),0);
buffer[num] = '\0';
printf("Message received: %s\n", buffer);
break;
}
}
close(sockfd);
return 0;
}
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 BACKLOG 10 // how many pending connections queue will hold
#define MAXDATASIZE 100 // max number of bytes we can get at once
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(int argc, char *argv[]) {
int sockfd; // set up socket
int new_sockfd; // new socket after connection
struct addrinfo hints, *results, *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 i;
struct timeval tv;
int num;
char buffer[10241];
int nsock;
char buf[MAXDATASIZE];
int numbytes;
char *port;
//select data
fd_set rfds;
fd_set wfds;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
/* validate command-line arguments */
if (argc != 2) {
fprintf(stderr, "Usage: %s port\n", argv[0]);
exit(1);
}
tv.tv_sec = 100;
tv.tv_usec = 0;
/* only argument to port number (./sc [port])*/
port = argv[1];
bzero(&hints, sizeof (struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // any IP
if ((rv = getaddrinfo(NULL, port, &hints, &results)) != 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 = results; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("1: 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(results); // 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");
while (1) { // main accept() loop
sin_size = sizeof their_addr;
new_sockfd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size);
if (new_sockfd == -1) {
perror("accept");
continue;
}
//get the clients info
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *) &their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
FD_SET(new_sockfd, &rfds);
FD_SET(new_sockfd, &wfds);
if (select(new_sockfd + 1, &rfds, &wfds, NULL, &tv) < 0) {
perror("select");
return -1;
}
if (FD_ISSET(new_sockfd, &rfds))
while (1) {
if ((num = recv(new_sockfd, buffer, 10240, 0)) == -1) {
//fprintf(stderr,"Error in receiving message!!\n");
perror("recv");
exit(1);
} else if (num == 0) {
printf("Connection closed\n");
return 0;
}
// num = recv(client_fd, buffer, sizeof(buffer),0);
buffer[num] = '\0';
printf("Message received: %s\n", buffer);
break;
}
if (FD_ISSET(new_sockfd, &wfds))
while (1) {
fgets(buffer, MAXDATASIZE - 1, stdin);
if ((send(new_sockfd, buffer, strlen(buffer), 0)) == -1) {
fprintf(stderr, "Failure Sending Message\n");
close(new_sockfd);
exit(1);
} else {
printf("Message being sent: %s\n", buffer);
break;
}
}
} //Outer While
close(new_sockfd); // parent doesn't need this
return 0;
}
The host and client aren't able to communicate. Can anyone tell me where the issue is?
You need to call select() inside of the loops, not outside. Also, you have to reset the fd_set and timeval structs each time you call select().