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?
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 have written an echo TCP server in C.
I wish to test my code to see if it works.
#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");
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
char buf[BUF_SIZE];
while(1){
ssize_t nread = recv(cfd, buf, BUF_SIZE, 0);
if (nread == 0) {
close(cfd);
exit(EXIT_SUCCESS);
} else {
ssize_t nsent = send(cfd, buf, nread, 0);
if (nsent != nread) fprintf(stderr, "Error sending response");
}
}
} else {
//Parent code
}
}
close(sfd);
}
It compiles just fine, but when I try running it as tcp_server 127.0.0.1 80 it gives me the error message Could not bind to any socket.
In my understanding, this should have bound the server to the IPv4 loopback address, port 80, and then I would have been able to interact with it using netcat.
What is going on?
Low-numbered ports are considered privileged by most operating systems. Try with a port like 8000 or 8080.
Since you are passing port 80 via command line argument i.e. ARGV[2]. The Port No. 80 is the port number assigned to commonly used internet communication protocol, Hypertext Transfer Protocol (HTTP).
You can use the port according to the below classification:
1. Ports 0–1023 – system or well-known ports
2. Ports 1024–49151 – user or registered ports
3. Ports >49151 – dynamic / private ports
So by this might, your problem will get solved.
I'm building a Client/Server distributed application via socket in C.
Here is my server:
#include <stdio.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <netinet/tcp.h>
#define LEN 20
int main(void) {
int err, nread, status, optval=1;
int sd, ns;
char category[LEN];
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if((err = getaddrinfo(NULL, "50000", &hints, &res)) != 0) {
printf("%s", gai_strerror(err));
exit(-1);
}
if((sd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
printf("Error in Socket Server\n");
exit(-1);
}
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
if(bind(sd, res->ai_addr, res->ai_addrlen) != 0) {
printf("Error in bind\n");
exit(-1);
}
freeaddrinfo(res);
if(listen(sd, 5) != 0) {
printf("Error in listen\n");
exit(-1);
}
for(;;) {
if((ns = accept(sd, NULL, NULL)) < 0) {
printf("Error in accept\n");
exit(-10);
}
/* I tried with this: setsockopt(ns, IPPROTO_TCP, TCP_NODELAY, (char*)&optval, sizeof(int));
but it didn't work out */
while((nread = read(ns, category, LEN)) > 0){
if(category[nread-1]=='\n') {
category[nread-1]='\0';
}
if(fork()==0) {
close(1);
dup(ns);
close(ns);
execlp("grep", "grep", category, "conto_corrente.txt", (char *)0);
perror("Error in fork\n");
exit(-100);
}
wait(&status);
}
close(ns);
}
}
And here is my client:
#include <stdio.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
int err, nread;
int sd;
char category[20];
char buff[1024];
struct addrinfo hints, *res, *ptr;
if(argc!=3) {
printf("Error in number of parameters\n");
exit(-1);
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if((err = getaddrinfo(argv[1], argv[2], &hints, &res)) != 0) {
printf("%s\n", gai_strerror(err));
exit(-1);
}
for(ptr = res; ptr != NULL; ptr=ptr->ai_next) {
if((sd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol)) < 0) {continue;}
if((connect(sd, ptr->ai_addr, ptr->ai_addrlen)) == 0) {
break;
}
}
if(ptr==NULL) {
printf("Error in connection\n");
exit(-1);
}
freeaddrinfo(res);
printf("Category: ");
scanf("%s", category);
while(strcmp(category, "fine") != 0) {
write(sd, category, strlen(category)+1);
while((nread = read(sd, buff, 1024)) > 0) {
printf("%s", buff);
}
printf("Category: ");
scanf("%s", category);
}
close(sd);
return 0;
}
The program should take an input from the user (a string) and send it to the server which have to scan the file and select all the lines that contain that string.
I think there is a problem in the buffering because when the user enter a string then the client stops it looks like it is waiting for something, in fact if I kill the server then the client shows what it read. How is it?