I'm learning C in posix standard. I'm trying to create client-server application, and right now I try to handle communication between them.
I didn't know how to properly let client know when he is supposed to send something to server. What I came up with is simple - when server sends message "1" it means it now waits for client's input.
I first tried with telnet and it somehow worked. Problems came when I created client application - it worked ONCE. And later it decided to stop working. Server properly gets one input from client (when he chooses "AddObject" option) and later it stops working (client doesn't know server waits for a message).
I've tried to clean up my code as much as possible (my actual code is a huge, since I often try different things and have a lot of comments), but it sill probably sucks - sorry for that.
server
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <stdbool.h>
#include <poll.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <ctype.h>
#define maxnamel 50
#define BUFLEN 512
#define ERR(source) (fprintf(stderr,"%s:%d\n",__FILE__,__LINE__),\
perror(source),kill(0,SIGKILL),\
exit(EXIT_FAILURE))
struct arg_struct {
int fd;
int org;
};
void usage(void);
int make_socket(uint16_t port);
void usage(void){
fprintf(stderr, "Usage: ./all\n");
exit(EXIT_FAILURE);
}
void sendAndPrint(char* wiadomosc, int sock){
write((int)sock , wiadomosc , strlen(wiadomosc));
printf("%s",wiadomosc);
}
int make_socket(uint16_t port) {
struct sockaddr_in name;
int sock, t=1;
sock = socket(PF_INET,SOCK_STREAM,0);
if (sock < 0) ERR("socket");
name.sin_family = AF_INET;
name.sin_port = htons(port);
name.sin_addr.s_addr = htonl(INADDR_ANY);
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t))) ERR("setsockopt");
if (bind(sock,(struct sockaddr*) &name, sizeof(name)) < 0) ERR("bind");
return sock;
}
void addObject (int sock)
{
int read_size, read_size_sum;
char* buf;
char *record;
record=malloc(sizeof(char)*100+1);
buf=malloc(sizeof(char)*10+1);
sendAndPrint("AddObject.\n", sock);
sendAndPrint("Add details of new object.\n", sock);
sendAndPrint("Name:\n", sock);
sleep(0.5);
sendAndPrint("1", sock);
read_size = recv(sock, buf, maxnamel, 0);
printf("%s", buf);
read_size-=1;
buf[read_size]=0;
read_size_sum = read_size;
strcpy(record,buf);
record[read_size-1]=0;
sendAndPrint("Age:\n", sock);
sendAndPrint("1\n", sock);
read_size = recv(sock, buf, 10, 0);
read_size-=1;
buf[read_size+1]=0;
read_size_sum +=read_size;
strcat(record,"-");
strcat(record,buf);
record[read_size_sum-2]=0;
sendAndPrint("Weight:\n", sock);
sendAndPrint("1", sock);
read_size = recv(sock, buf, 10, 0);
buf[read_size-1]=0;
read_size_sum +=read_size;
strcat(record,"-");
strcat(record,buf);
record[read_size_sum-3]=0;
sendAndPrint("Number:\n", sock);
sendAndPrint("1", sock);
read_size = recv(sock, buf, 10, 0);
buf[read_size-1]=0;
read_size_sum +=read_size;
strcat(record,"-");
strcat(record,buf);
record[read_size_sum-3]=0;
strcat(record,"-0");
strcat(record,"\n");
}
void *connection_handler(void *sock_desc)
{
return 0;
}
void *organizer_handler(void *sock_desc)
{
int wybor, read_size;
char client_message[1000];
int sock = *(int*)sock_desc;
sendAndPrint("Start.\n",sock);
sendAndPrint("Choose your action:\n\n1 - Add Object\n2 - To Do\n3 - To Do\n",sock);
sendAndPrint("4 - To Do\n\n\n", sock);
sendAndPrint("1", sock);
while((read_size = recv(sock , client_message , 100 , 0)) > 0 )
{
wybor=atoi(client_message);
if((wybor==1))
addObject(sock);
else
{
sendAndPrint("Wrong choice.\n\n",sock);
sleep(3);
}
sendAndPrint("Choose your action:\n\n1 - Add Object\n2 - To Do\n3 - To Do\n",sock);
sendAndPrint("4 - To Do\n\n\n", sock);
}
return 0;
}
void *doClient(void *arguments){
struct arg_struct *args = arguments;
int fd = args -> fd;
int org = args -> org;
int backlog=10;
int l, c,client_sock, *new_sock;
fd_set set;
pthread_t sniffer_thread2;
struct sockaddr_in client;
l=listen(fd, backlog);
c = sizeof(struct sockaddr_in);
puts("Thread created.");
while(1)
{
FD_ZERO(&set);
FD_SET (fd, &set);
puts("Waiting for connection...");
while((client_sock = accept(fd, (struct sockaddr *)&client, (socklen_t*)&c)))
{
new_sock = malloc(1);
*new_sock = client_sock;
if (org == 1)
{
puts("Organizer has connected. Creating thread...");
if( pthread_create( &sniffer_thread2 , NULL , organizer_handler , (void*) new_sock) < 0)
{
perror("Could not create thread for organizer.");
return 0;
}
} else
{
puts("Normal client has connected. Creating thread...");
if( pthread_create( &sniffer_thread2 , NULL , connection_handler , (void*) new_sock) < 0)
{
perror("Could not create thread for normal client.");
return 0;
}
}
}
}
return 0;
}
void doServer(int fd){
pthread_t sniffer_thread;
char message[1000];
struct arg_struct orgArgs;
orgArgs.fd = fd;
orgArgs.org = 1;
puts("Started server.");
puts("Creating a thread for organizer client...");
if( pthread_create( &sniffer_thread , NULL , doClient , (void *)&orgArgs) < 0)
{
perror("Could not create thread for doClient for organizers.");
return;
}
puts("Type 1 if you want to stop server.");
while (scanf("%s", message))
{
if(atoi(message) == 1)
{
puts("Closing server.");
break;
}
else
puts("Type 1 if you want to stop server.");
}
}
int main(int argc, char** argv) {
int fd;
uint16_t port=8089;
if(argc != 1){
usage();
}
fd = make_socket(port);
doServer(fd);
return EXIT_SUCCESS;
}
client
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <stdbool.h>
#include <poll.h>
#include <netdb.h>
#define HERR(source) (fprintf(stderr,"%s(%d) at %s:%d\n",source,h_errno,__FILE__,__LINE__),\
exit(EXIT_FAILURE))
#define BUFLEN 512
#define ERR(source) (fprintf(stderr,"%s:%d\n",__FILE__,__LINE__),\
perror(source),kill(0,SIGKILL),\
exit(EXIT_FAILURE))
int fd;
int make_socket(void){
int sock;
sock = socket(PF_INET,SOCK_STREAM,0);
if(sock < 0) ERR("socket");
return sock;
}
struct sockaddr_in make_address(uint16_t port){
struct sockaddr_in addr;
struct hostent *hostinfo;
addr.sin_family = AF_INET;
addr.sin_port = htons (port);
hostinfo = gethostbyname("localhost");
if(hostinfo == NULL)HERR("gethostbyname");
addr.sin_addr = *(struct in_addr*) hostinfo->h_addr;
return addr;
}
int connect_socket(uint16_t port){
struct sockaddr_in addr;
int socketfd;
socketfd = make_socket();
addr=make_address(port);
if(connect(socketfd,(struct sockaddr*) &addr,sizeof(struct sockaddr_in)) < 0){
if(errno!=EINTR) ERR("connect");
else {
fd_set wfds;
int status;
socklen_t size = sizeof(int);
FD_ZERO(&wfds);
FD_SET(socketfd, &wfds);
if(TEMP_FAILURE_RETRY(select(socketfd+1,NULL,&wfds,NULL,NULL))<0) ERR("select");
if(getsockopt(socketfd,SOL_SOCKET,SO_ERROR,&status,&size)<0) ERR("getsockopt");
if(0!=status) ERR("connect");
}
}
return socketfd;
}
void doClientORG(int fd){
int read_size;
int msg_size;
char client_message[1000];
char message[1000];
puts("Waiting for server.");
while((read_size = recv(fd , client_message , 100 , 0)) > 0 )
{
client_message[read_size]=0;
if(atoi(client_message) == 1)
{
puts("Inside");
scanf("%s", message);
/*printf("Message: %s\n\n", message);*/
write(fd, message,1);
}
else
printf("%s", client_message);
}
}
int main(int argc, char** argv) {
int fd;
uint16_t port=8089;
char* message;
fd=connect_socket(port);
doClientORG(fd);
return EXIT_SUCCESS;
}
Any ideas? Did I do something wrong, or is my idea incorrect to begin with?
Related
I am trying to broadcast a UDP message from the server to client. I would like for the server to send the broadcast to the client and then for the client to acknowledge the broadcast. They both compile with no errors but the server will not send the broadcast. The server says it successfully binds. Any tips would be helpful please.
Client.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#define PORT 8081
int main (int argc, char* argv[]){
int clientsocket;
int reuse = 1;
int reuseaddr;
int bind_sock;
int rec_broad;
int send_ack;
char dgram[512];
char client_message[2000];
struct sockaddr_in serv_address;
struct sockaddr_in group;
if (argc != 3) {
printf("Command line args should be multicast group and port\n");
printf("(e.g. for SSDP, `listener 239.255.255.250 1900`)\n");
return 1;
}
clientsocket = socket(AF_INET, SOCK_DGRAM, 0);
if(clientsocket < 0){
printf("\n\tSocket not created.\n");
exit(1);
}
else printf("\n\tSocket created successfully.\n");
reuseaddr = setsockopt(clientsocket, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));
if(reuseaddr < 0){
printf("\n\tSetting REUSEADDR error.\n");
exit(1);
}
else printf("\n\tREUSEADDR Successful.\n");
serv_address.sin_family = AF_INET;
serv_address.sin_port = htons(PORT);
serv_address.sin_addr.s_addr = inet_addr(argv[1]);
/*bind_sock = bind(clientsocket, (struct sockaddr*) &serv_address, sizeof(serv_address));
if(bind_sock < 0){
printf("\n\tBind unsuccessful.\n");
exit(1);
}
else printf("\n\tBind Successful.\n");*/
strcpy(client_message, "Acknowledged.\n");
for(;;){
printf("\nListening........\n");
rec_broad = recvfrom(clientsocket, dgram, sizeof(dgram), 0, (struct sockaddr*) &serv_address, sizeof(serv_address));
if(rec_broad < 0){
printf("\n\tBroadcast not received.\n");
exit(1);
}
else printf("\n\tBroadcast received successfully.\n");
send_ack = sendto(clientsocket, client_message, sizeof(client_message), 0, (struct sockaddr*)&serv_address, sizeof(serv_address));
if (send_ack < 0){
printf("\n\tAck not sent.\n");
}
else printf("\n\tAcknowledge sent successfully.\n");
}
return 0;
}
Server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8081
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
int main (int argc, char *argv[]){
int serv_socket;
struct sockaddr_in broadcast_addr;
struct sockaddr_in client_addr;
int b_addr_len;
int ret;
int bind_sock;
int yes = 1;
char buffer[2000];
int send_broad;
int z;
//Create socket
serv_socket = socket(AF_INET, SOCK_DGRAM, 0);
if(serv_socket < 0){
printf("\n\tProblem1.\n");
exit(1);
}
else printf("\n\tSocket made successful.\n");
//Setsockopt
ret = setsockopt(serv_socket, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(yes));
if(ret < 0){
printf("\n\tSetsockopt error.\n");
return -1;
}
else printf("\n\tSetsockopt successful.\n");
b_addr_len = sizeof(broadcast_addr);
//Broadcast Address
memset((void*)&broadcast_addr, 0, b_addr_len);
broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_addr.s_addr = inet_addr(argv[1]);
broadcast_addr.sin_port = htons(atoi(argv[2]));
//Bind socket with client
bind_sock = bind(serv_socket, (struct sockaddr*) &client_addr, b_addr_len);
if (ret < 0){
printf("\n\tBind unsuccessful.\n");
exit(1);
}
else printf("\n\tBind successful.\n");
memset(buffer, '\0', 2000);
strcpy(buffer, "This is the broadcast!\n");
//Send broadcast
send_broad = sendto(serv_socket, buffer, sizeof(buffer), 0, (struct sockaddr*)&broadcast_addr, b_addr_len);
if(send_broad < 0){
printf("\n\tBroadcast not sent.\n");
exit(1);
}
else printf("\n\tBroadcast sent OK.\n");
return 0;
}
I have client-server program where I created the socket with sctp protocol and client and server has a onetomany relation.
when I run the client code the return value of sendto function is greater than zero. But I don't see any message in the server code output.
Even when the server code is not running and only the client code is running, the client code shows successful message sent. How can it be when the server sockeet is not even open?
/*
* Compile:
*
* gcc sctp.c -o server -lsctp
*
* Invoke:
*
* ./client
* ./server
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#define MY_PORT_NUM 21233
static void die(const char *s) {
perror(s);
exit(1);
}
static void server(void) {
int listen_fd, conn_fd, flags, ret, in;
struct sctp_sndrcvinfo sndrcvinfo;
struct sockaddr_in servaddr = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_ANY),
.sin_port = htons(MY_PORT_NUM),
};
struct sockaddr_in client_addr;
socklen_t clilen=sizeof(client_addr);
struct sctp_initmsg initmsg = {
.sinit_num_ostreams = 5,
.sinit_max_instreams = 5,
.sinit_max_attempts = 4,
};
listen_fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
if (listen_fd < 0)
die("socket");
ret = bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
if (ret < 0)
die("bind");
ret = listen(listen_fd, initmsg.sinit_max_instreams);
if (ret < 0)
die("listen");
for (;;) {
char buffer[1024];
printf("Waiting for connection\n");
in = recvfrom(listen_fd, buffer, sizeof(buffer),0,(struct sockaddr*)&client_addr,&clilen);
printf("%d\n",in);
if (in > 0) {
printf("Received data: %s\n", buffer);
fflush(stdout);
}
sleep(2);
}
close(listen_fd);
}
static void client(void) {
int conn_fd, ret;
const char *msg = "Hello, Server!";
struct sockaddr_in servaddr = {
.sin_family = AF_INET,
.sin_port = htons(MY_PORT_NUM),
.sin_addr.s_addr = inet_addr("127.0.0.1"),
};
conn_fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
if (conn_fd < 0)
die("socket()");
int i;
for(i=0;i<4;i++){
printf("before sending\n");
ret = sendto(conn_fd, (void *) msg, strlen(msg) + 1,0,(struct sockaddr*)&servaddr,sizeof(struct sockaddr));
printf("after sending\n");
if (ret < 0)
printf("failed to send %d\n",i);
else
printf("success %d\n",i);
sleep(2);
}
close(conn_fd);
}
int main(int argc, char **argv) {
if (strstr(basename(argv[0]), "server"))
server();
else
client();
return 0;
}
this code works when I run the client and server in same machine with loopback IP 127.0.0.1 but when I run them on two different remote machines I am facing this issue.
(sorry by advance for my English...)
I am working on a network between a PC and a set of Zedboards connected by Ethernet. I use the UDP protocol, and here's my problem:
- All my cards and my PC are correctly connected to a switch and have their own IPs (192.168.1.15 for PC , and 11/12 for cards).
- When I try to send a simple packet with unix sockets with the code below, only the last message is received (but both seem to be send) (plus, no error or warning on compilation)
- If I switch the two sending, it is always the last which arrive at destination so it is not a card problem...
main.c
#include "send_tool.h"
static int PORT;
static char LOCAL_ADDRESS[50];
static SOCKADDR_IN client_list[NB_CLIENTS];
static int uc_sock;
int main(int argc, char **argv)
{
char buffer[BUF_SIZE];
int actual;int i;
memset(buffer,0, sizeof(buffer));
SOCKADDR_IN csin = { 0 };
if(argc < 3)
{
PORT = 2005;
sprintf(LOCAL_ADDRESS, "192.168.1.15");
printf("Valeurs de parametre forcees: %d\t%s\n", PORT, LOCAL_ADDRESS);
}
else
{
PORT = atoi(argv[1]);
sprintf(LOCAL_ADDRESS, argv[2]);
}
uc_sock = init_UC_connection(LOCAL_ADDRESS, PORT);
while(actual < NB_CLIENTS)
{
read_UDP(uc_sock, &csin, buffer);
if(!strncmp(buffer, "free:",5))
{
//add_client(client_list, csin);
client_list[actual].sin_addr.s_addr = csin.sin_addr.s_addr;
client_list[actual].sin_port = csin.sin_port;
client_list[actual].sin_family = csin.sin_family;
memcpy(client_list[actual].sin_zero, csin.sin_zero, 8);
//sprintf(buffer, "salut");
//write_UDP(uc_sock, &client_list[actual], buffer, strlen(buffer));
actual++;
}
}
printf("************************************\n");
printf("0: %s:%d/%d\n", inet_ntoa(client_list[0].sin_addr), ntohs(client_list[0].sin_port), client_list[0].sin_family);
printf("1: %s:%d/%d\n", inet_ntoa(client_list[1].sin_addr), ntohs(client_list[1].sin_port), client_list[1].sin_family);
printf("************************************\n");
sprintf(buffer, "au revoir");
write_UDP(uc_sock, &client_list[0], buffer, strlen(buffer));
write_UDP(uc_sock, &client_list[1], buffer, strlen(buffer));
memset(buffer, 0, sizeof(buffer));
while(read_UDP(uc_sock, &csin, buffer) > 0){}
close(uc_sock);
return 0;
}
send_tool.h
/* STD LIBS */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
//#include <sys/types.h>
//#include <sys/stat.h>
/* SOCKETS */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
/* TIME */
#include <sys/timerfd.h>
#include <sys/time.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#define BUF_SIZE 60000
#define MULTICAST_ADDRESS "224.0.0.1"
#define NB_CLIENTS 2
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
typedef struct in_addr IN_ADDR;
int init_UC_connection(char LOCAL_ADDRESS[], int port);
void write_UDP(int sock, SOCKADDR_IN *sin, const char *buffer, size_t buff_len);
int read_UDP(int sock, SOCKADDR_IN *sin, char *buffer);
send_tool.c
#include "send_tool.h"
int init_UC_connection(char LOCAL_ADDRESS[], int port)
{
/* UDP so SOCK_DGRAM */
int sock = socket(AF_INET, SOCK_DGRAM, 0);
SOCKADDR_IN sin = { 0 };
struct timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 0;
if(sock == -1)
{
perror("socket()");
exit(errno);
}
sin.sin_addr.s_addr = inet_addr(LOCAL_ADDRESS);
sin.sin_port = htons(port);
sin.sin_family = AF_INET;
if(bind(sock,(SOCKADDR *)&sin, sizeof sin) == -1)
{
perror("bind()");
exit(errno);
}
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) < 0) {
perror("Error");
}
return sock;
}
void write_UDP(int sock, SOCKADDR_IN *sin, const char *buffer, size_t buff_len)
{
socklen_t sinsize = 16;//sizeof *sin;
printf("sinsize : %d\n", sinsize);
int n;
size_t i;
if((n=sendto(sock, buffer, buff_len, 0, (SOCKADDR *) sin, sinsize)) < 0)
{
perror("send()");
exit(errno);
}
printf("envoi (sinsize = %d; n = %d)|%s| a %s:%d/%d termine \n", sinsize, n, buffer, inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), sin->sin_family);
}
int read_UDP(int sock, SOCKADDR_IN *sin, char *buffer)
{
int n = 0;
socklen_t sinsize = sizeof *sin;
if((n = recvfrom(sock, buffer, BUF_SIZE - 1, 0, (SOCKADDR *) sin, &sinsize)) < 0)
{
perror("recvfrom()");
exit(errno);
}
printf("recu (sinsize = %d; n = %d)|%s| depuis %s:%d/%d termine \n", sinsize, n, buffer, inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), sin->sin_family);
return n;
}
client.c
#include "receive_tool.h"
static int PORT;
static char LOCAL_ADDRESS[50];
/* main function, launching the Server application*/
int main(int argc, char **argv)
{
int uc_sock;
char free_msg[30];
memset(free_msg, 0, sizeof(free_msg));
char buffer[60000];
memset(buffer, 0, sizeof(buffer));
if(argc < 3)
{
PORT = 2005;
sprintf(LOCAL_ADDRESS, "192.168.1.12");
//printf("Valeurs de parametre forcees: %d\t%s\n", PORT, LOCAL_ADDRESS);
}
else
{
PORT = atoi(argv[1]);
sprintf(LOCAL_ADDRESS, argv[2]);
}
sprintf(free_msg, "free:%s", LOCAL_ADDRESS);
SOCKADDR_IN server_sin = { 0 }, receive_sin = { 0 };
server_sin.sin_addr.s_addr = inet_addr(SERVER_ADDRESS); // addresse multicast vers les serveurs
server_sin.sin_family = AF_INET;
server_sin.sin_port = htons(PORT);
memset(&server_sin.sin_zero, 0, sizeof(server_sin.sin_zero));
uc_sock = init_UC_connection(LOCAL_ADDRESS, PORT);
write_UDP(uc_sock, &server_sin, free_msg);
time_t chrono_begin;
chrono_begin = time(NULL);
chrono_begin+= 5;
while(time(NULL) <= chrono_begin)
{
if(read_UDP(uc_sock, &receive_sin, buffer)<0) continue;
write_UDP(uc_sock, &server_sin, buffer);
}
close(uc_sock);
return 0;
}
Do you have any idea why this happen?
Thank you for your help.
The problem was caused by the Zedboards which used the same MAC address. Then, the switch sent only to the last IP address connected to the MAC address.
Bye
I have a multi-threaded client that can transfer a batch of files to a new directory that the client itself makes. My client used to use a single-threaded server.
For an assignment I'm supposed to transform my single-threaded server into a multi-threaded server that creates a new thread for each client request. I'm also supposed to time the whole operation and output it to the client (which I got to work when the server was single threaded). The code for both the multi-threaded client (which works with a single-thread server) and the multi-thread server (which does not work well) are below:
client.c
#include <sys/uio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <netdb.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <string.h>
#include <strings.h>
#include "Timer.h"
#define N_THREADS 10
char * files[] = {
"/usr/share/dict/words",
"/usr/include/sqlite3.h",
"/usr/include/tclDecls.h",
"/usr/include/bfd.h",
"/usr/include/libmng.h",
"/usr/include/elf.h",
"/usr/include/gmpxx.h",
"/usr/include/tkDecls.h",
"/usr/include/H5overflow.h",
"/usr/include/tcl.h",
"/usr/include/gmp-x86_64.h",
"/usr/include/curses.h",
"/usr/include/lcms.h",
"/usr/include/netapi.h",
"/usr/include/gcrypt.h",
"/usr/include/zlib.h",
"/usr/include/ldap.h",
"/usr/include/geos_c.h",
"/usr/include/kdb.h",
"/usr/include/tk.h",
"/usr/include/yaml.h"
};
#define files_length() (sizeof files / sizeof files[0])
void error(char *msg)
{
perror(msg);
exit(-1);
}
struct sockaddr_in make_server_addr(char *host, short port)
{
struct sockaddr_in addr;
bzero(&addr, sizeof addr);
struct hostent *hp = gethostbyname(host);
if ( hp == 0 )
error(host);
addr.sin_family = AF_INET;
bcopy(hp->h_addr_list[0], &addr.sin_addr, hp->h_length);
addr.sin_port = htons(port);
return addr;
}
int connect_socket(char *host, short port)
{
int status;
int tries = 3;
struct sockaddr_in addr = make_server_addr(host, port);
int s = socket(AF_INET, SOCK_STREAM, 0);
if ( s == -1 )
error("socket()");
status = connect(s, (struct sockaddr*)&addr, sizeof addr);
if ( status < 0 )
error("connect refused");
return s;
}
void request_file_from_server(int server_socket, char *file)
{
int len = strlen(file);
int n = write(server_socket, file, len);
if ( n != len )
error("short write");
}
void read_file_from_server(int server_socket, char *file)
{
char buf[BUFSIZ];
int n;
mode_t mode = 0666;
int ofd = open(file, O_WRONLY | O_CREAT, mode);
if ( ofd == -1 )
perror("open()");
while ( (n = read(server_socket, buf, BUFSIZ)) > 0 )
write(ofd, buf, n);
close(ofd);
}
struct Thread_data
{
int id;
pthread_t thread_id;
char * host;
short port;
char path[BUFSIZ];
};
void make_file_name(char *local_name, char *dir, char *original_path)
{
char *p = rindex(original_path, '/');
if ( !p )
error("rindex()");
sprintf(local_name, "%s/%s", dir, p+1);
}
int remote_copy(struct Thread_data * data, char * file)
{
int server_socket = connect_socket(data->host, data->port);
request_file_from_server(server_socket, file);
char local_name[BUFSIZ];
make_file_name(local_name, data->path, file);
read_file_from_server(server_socket, local_name);
close(server_socket);
}
void make_empty_dir_for_copies(struct Thread_data * data)
{
mode_t mode = 0777;
sprintf(data->path, "./Thread_%d", (data->id + 1));
mkdir(data->path, mode);
}
#define N_FILES_TO_COPY files_length() // copy them all
void *thread_work(void *arg)
{
struct Thread_data * data = (struct Thread_data *)arg;
make_empty_dir_for_copies(data);
for ( int i=0; i < N_FILES_TO_COPY; ++i )
remote_copy(data, files[i]);
pthread_exit(0);
}
void start_threads(char *host, short port, struct Thread_data thread_args[])
{
for ( int i = 0; i < N_THREADS; ++i )
{
struct Thread_data * t = &thread_args[i];
t->id = i;
t->host = host;
t->port = port;
pthread_create(&t->thread_id, NULL, thread_work, t);
}
}
void join_threads(struct Thread_data thread_args[], double *eTime)
{
for ( int i=0; i < N_THREADS; i++ )
pthread_join(thread_args[i].thread_id, NULL);
Timer_elapsedUserTime(eTime);
printf("Elapsed time for transferring all files: %lf\n", *eTime);
pthread_exit(0);
}
int main(int argc, char *argv[])
{
if ( argc != 3 )
{
fprintf(stderr, "Usage: %s host port\n", argv[0]);
exit(-1);
}
struct Thread_data thread_args[N_THREADS];
char *host = argv[1];
short port = atoi(argv[2]);
double eTime;
Timer_start();
start_threads(host,port,thread_args);
join_threads(thread_args, &eTime);
}
server.c
#include <sys/types.h>
#include <signal.h>
#include <sys/uio.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <pthread.h>
#include <string.h>
#include "Timer.h"
#define BACKLOG 200
// more than this in the queue, and client connect will fail
#define NUM_THREADS 200
void error(char *msg)
{
fprintf(stderr, "%s\n", msg);
exit(-1);
}
struct sockaddr_in make_server_addr(short port)
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
return addr;
}
int create_server_socket(short port)
{
int s = socket(AF_INET, SOCK_STREAM, 0);
int optval = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
struct sockaddr_in my_addr = make_server_addr(port);
if ( s == -1 )
error("socket()");
bind(s, (struct sockaddr*)&my_addr, sizeof my_addr);
listen(s, BACKLOG);
return s;
}
void get_file_request(int socket, char *fileName)
{
char buf[BUFSIZ];
int n = read(socket, buf, BUFSIZ);
if ( n < 0 )
error("read from socket");
buf[n] = '\0';
strcpy(fileName, buf);
printf("Server got file name of '%s'\n", fileName);
}
void write_file_to_client_socket(char *file, int socket)
{
char buf[BUFSIZ];
int n;
int ifd = open(file, O_RDONLY);
if ( ifd == -1 )
error("open()");
while ( (n = read(ifd, buf, BUFSIZ)) > 0 )
write(socket, buf, n);
close(ifd);
}
void * handle_request(void * c_socket)
{
int *client_socket = (int*)c_socket;
char fileName[BUFSIZ];
get_file_request(*client_socket, fileName);
write_file_to_client_socket(fileName, *client_socket);
close(*client_socket);
pthread_exit(0);
return NULL;
}
void time_out(int arg)
{
fprintf(stderr, "Server timed out\n");
exit(0);
}
void set_time_out(int seconds)
{
struct itimerval value = {0};
// bzero(&value, sizeof value);
/* timerclear(&value.it_interval); timerclear(&value.it_value); */
value.it_value.tv_sec = seconds;
setitimer(ITIMER_REAL, &value, NULL);
signal(SIGALRM, time_out);
}
void accept_client_requests(int server_socket)
{
pthread_t threads;
int client_socket;
struct sockaddr_in client_addr;
socklen_t sin_size = sizeof client_addr;
set_time_out(10);
while ( (client_socket =
accept(server_socket, (struct sockaddr*)&client_addr, &sin_size)) )
{
set_time_out(10);
pthread_create(&threads,0, handle_request,&client_socket);
}
}
int main(int argc, char *argv[])
{
if ( argc != 2 )
error("usage: server port");
short port = atoi(argv[1]);
int server_socket = create_server_socket(port);
accept_client_requests(server_socket);
shutdown(server_socket, 2);
return 0;
}
The issue happens when using handle_request when I am using accept and creating a new pthread. It gets to whatever the last file is (in this case /usr/include/yaml.h), hangs and then times out. Without a timeout it would hang indefinitely.
I don't really know much about multi-threading with pthreads, so I'm just going off of my professors instructions which basically said to create the thread and handle the request like you would in a single threaded server. In my single threaded server, handle_request was passed in an int (which now gets converted).
Does anyone know why my server would hang on the last transferred file until it times out?
There's a flaw in the accept_client_requests function. You have a variable
int client_socket;
The address of that variable is passed to pthread_create
pthread_create(&threads,0, handle_request,&client_socket);
pthread_create passes the pointer to handle_request which stores it as a local pointer
int *client_socket = (int *)c_socket;
The problem is that the pointer is still pointing to the client_socket variable in the accept_client_requests function. So when accept_client_requests gets another connection, the client_socket is changed, and every thread currently running has its client_socket changed, which should cause all sorts of chaos.
The solution is to malloc an int to hold the client_socket, and then pass that address to the thread.
int *temp = malloc( sizeof(int) );
*temp = client_socket;
pthread_create(&threads, 0, handle_request, temp);
pthread_detach(threads);
When the thread is finished, it should free the memory.
The accept_client_requests function should also call pthread_detach on every thread that it creates, so that resources can be reclaimed when the thread finishes.
Without the pthread_detach the system will expect to see a pthread_join before cleaning up the thread.
I am trying to create a client server application whose code I have attached below. I want to use this as a single node for my network which consists of both server and client. This node will be used in future for communicating with other nodes(same code will be run on different machines)
Now I am creating a thread for both client and server functions which should run alternatively through context switching using my own thread library. Following is the code for my client server node
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "so.h"
#include <sched.h>
#include <openssl/sha.h>
char s[50];
void *client()
{
int port=5000;
int sockfd = 0,n = 0,i=0;
char recvBuff[1024],sendBuff[1025];
struct sockaddr_in serv_addr;
printf("Inside client\n");
memset(recvBuff, '0' ,sizeof(recvBuff));
while(1){
printf("running client for %dth time\n",i++);
if((sockfd = socket(AF_INET, SOCK_STREAM, 0))< 0)
{
printf("\n Error : Could not create socket \n");
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0)
{
printf("\n Error : Connect Failed \n");
}
else
{
strcpy(sendBuff, "Hi");
send(sockfd, sendBuff, strlen(sendBuff),0);
}
while((n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
{
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF)
{
printf("\n Error : Fputs error");
}
printf("\n");
}
if( n < -1)
{
printf("\n Read Error \n");
}
sleep(1);
close(sockfd);
}
// return 0;
}
void *server( )
{
int port =5000;
printf("Inside server\n");
int listenfd = 0,connfd = 0,n = 0;
struct sockaddr_in serv_addr;
char sendBuff[1025],recvBuff[1024];
int numrv;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
printf("socket retrieve success\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', sizeof(sendBuff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(port);
bind(listenfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr));
if(listen(listenfd, 10) == -1){
printf("Failed to listen\n");
return;
}
printf("Binding done\n");
while(1)
{
connfd = accept(listenfd, (struct sockaddr*)NULL ,NULL); // accept awaiting request
strcpy(sendBuff, "Message from server1");
write(connfd, sendBuff, strlen(sendBuff));
n=recv(connfd, sendBuff, 1024, 0); //if hi received by the client,then server should receive "Message Received" from the client
sendBuff[n]='\0';
printf("%s\n", sendBuff);
close(connfd);
sleep(1);
}
// return 0;
}
int main(int argc,char **argv)
{
printf("Getting IP addr");
char *ip;
struct hostent *HostEntPtr;
struct in_addr in;
char Hostname[100];
gethostname( Hostname, sizeof(Hostname) );
HostEntPtr = gethostbyname( Hostname );
if ( HostEntPtr != NULL )
{
memcpy( &in.s_addr, *HostEntPtr->h_addr_list, sizeof(in.s_addr) );
ip = inet_ntoa(in);
printf( "ip address is %s\n", ip );
}
printf("Running client and server \n");
create(server);
create(client);
start();
while(1);
return 0;
}`
Following is the code for my thread library which uses SIGSETJMP and SIGLONGJMP. File name is so.h
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
#include <stdlib.h>
#include <sys/time.h>
#define SECOND 1000000
#define STACK_SIZE 4096
#define QUANTUM 1
void return_function();
struct thread
{
int flag;
int thread_id;
void *arg;
void *ret;
jmp_buf Env;
char stack[STACK_SIZE];
struct thread *next;
void (*func)(void);
void* (*func1)(void*);
}*front_readyqueue,*rear_readyqueue,*current_thread,*temp,*previous;
struct thread *front_created,*rear_created;
#ifdef __x86_64__
typedef unsigned long address_t;
#define JB_BP 1
#define JB_SP 6
#define JB_PC 7
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%fs:0x30,%0\n"
"rol $0x11,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
#else
typedef unsigned int address_t;
#define JB_BP 3
#define JB_SP 4
#define JB_PC 5
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%gs:0x18,%0\n"
"rol $0x9,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
#endif
int id=0;
int create(void (*f)(void))
{
address_t sp, pc,rt;
temp = (struct thread *)malloc(sizeof(struct thread));
id=id+1;
temp->thread_id=id;
temp->func=f;
sp = (address_t)temp->stack + STACK_SIZE - sizeof(address_t);
pc = (address_t)return_function;
sigsetjmp(temp->Env, 1);
(temp->Env->__jmpbuf)[JB_SP] = translate_address(sp);
(temp->Env->__jmpbuf)[JB_PC] = translate_address(pc);
(temp->Env->__jmpbuf)[JB_BP] = translate_address(rt);
sigemptyset(&temp->Env->__saved_mask);
if (front_readyqueue == NULL)
{
front_readyqueue=temp;
front_readyqueue->next=NULL;
rear_readyqueue=front_readyqueue;
printf("Thread %d created \n",id);
}
else
{
rear_readyqueue->next=temp;
rear_readyqueue=rear_readyqueue->next;
rear_readyqueue->next=front_readyqueue;
printf("Thread %d created \n",id);
}
return id;
}
void dispatch(int sig)
{
int i,j;
struct thread *temp_dispatch;
int ret_val = sigsetjmp(current_thread->Env,1);
printf("SWITCH: ret_val=%d\n", ret_val);
if (ret_val == 1) {
return;
}
current_thread=current_thread->next;
printf("switching to Thread %d \n",current_thread->thread_id);
longjmp(current_thread->Env,1);
}
void alarm_handler(int dummy)
{
alarm(QUANTUM);
signal(SIGALRM, alarm_handler);
dispatch(1);
}
void start()
{
printf("START \n");
long start_time=time(0);
signal(SIGALRM, alarm_handler);
alarm(QUANTUM);
current_thread=front_readyqueue;
siglongjmp(current_thread->Env, 1);
}
void return_function()
{
void *var;
struct thread *temp_rt=current_thread,*temp1,*node;
temp_rt->func();
signal(SIGALRM,SIG_IGN);
alarm(QUANTUM);
signal(SIGALRM, alarm_handler);
dispatch(1);
}
Following is the error dump
Getting IP addrip address is 10.208.20.204
Running client and server
Thread 1 created
Thread 2 created
START
Inside server
socket retrieve success
Binding done
SWITCH: ret_val=0
switching to Thread 2
Inside client
running client for 0th time
SWITCH: ret_val=0
switching to Thread 0
Segmentation fault (core dumped)
PS: When I try to create a thread on normal functions which does not use any blocking call then switching is taking place perfectly fine. I think that switching problem that I am facing is because of blocking calls used in server and client function. Any help would be appreciated. Thanks in advance