Related
After the first child thread exits, the process ends in Linux socket.
Please point the error,thanks.
After I close the first client thread, the main process close,too.
I don't know how to modify the code.
The following is my whole codes.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#define BUF_SIZE 1024
#define CONNECT_INFO 100
#define CLIENT_SIZE 100
int serv_port = 20000;
pthread_mutex_t mutex;
int clintQueue[CLIENT_SIZE];
int front = 0, rear = 0;
void error_handle(char *message);
void *read_func(void *clnt_sock);
int send_message(int socketFd, char *message, int len);
void error_handle(char *message)
{
perror(message);
exit(-1);
}
int send_message(int socketFd, char *message, int len)
{
pthread_mutex_lock(&mutex);
int ret = write(socketFd, message, len);
if (ret <= 0)
{
perror("write error");
}
pthread_mutex_unlock(&mutex);
return ret <= 0 ? 0 : 1;
}
void *read_func(void *arg)
{
// pthread_detach(pthread_self());
int clnt_sock = *(int *)arg;
char buf[BUF_SIZE];
int message_len;
while ((message_len = read(clnt_sock, buf, BUF_SIZE)) != 0)
{
buf[message_len] = 0;
printf("%s", buf);
send_message(clnt_sock, buf, message_len - 1);
memset(buf, 0, BUF_SIZE);
}
pthread_mutex_lock(&mutex);
printf("client %d[queue is %d]log out\n", clnt_sock, clintQueue[front]);
front++;
pthread_mutex_unlock(&mutex);
close(clnt_sock);
return NULL;
}
int main(int argc, char *argv[])
{
char clientInfo[CONNECT_INFO];
int serv_sock, clnt_sock;
socklen_t clnt_addr_len;
pthread_t read_id; //线程id
struct sockaddr_in serv_addr, clnt_addr;
pthread_mutex_init(&mutex, NULL);
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
if (serv_sock < 0)
{
perror("serv_sock create failed!");
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(serv_port);
serv_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
error_handle("bind fail");
}
else
{
puts("bind success");
}
if (listen(serv_sock, CLIENT_SIZE) < 0)
{
error_handle("listen fail");
}
else
{
puts("listen success");
}
while (1)
{
clnt_addr_len = sizeof(clnt_addr);
clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_addr_len);
if (clnt_sock < 0)
{
puts("clnt_sock < 0");
close(clnt_sock);
}
if (front == (rear + 1) % CLIENT_SIZE)
{
puts("client queue has flowed, connect failed");
close(clnt_sock);
}
else
{
memset(clientInfo, 0, sizeof(clientInfo));
pthread_mutex_lock(&mutex);
clintQueue[rear++] = clnt_sock;
pthread_mutex_unlock(&mutex);
// debug rear
printf("%d\n", rear);
puts("client queue add");
sprintf(clientInfo, "clientInfo[fd:%d, ip:%s, port:%d] has connected!", clnt_sock, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));
puts(clientInfo);
pthread_create(&read_id, NULL, read_func, (void *)&clnt_sock);
pthread_detach(read_id);
printf("thread %ld create success!\n", (pthread_t)read_id);
}
}
close(serv_sock);
pthread_mutex_destroy(&mutex);
return 0;
}
I want to use a main thread to control the connection, and the child threads to handle sending and receiving
On my computer, the application seems to behave fine:
florian#florian-desktop:~$ ./a.out
bind success
listen success
1
client queue add
clientInfo[fd:4, ip:127.0.0.1, port:33730] has connected!
thread 140353384478272 create success!
client 4[queue is 4]log out
2
client queue add
clientInfo[fd:5, ip:127.0.0.1, port:33732] has connected!
thread 140353384478272 create success!
this is a test
client 5[queue is 5]log out
I connected two telnet sessions to the application. I killed the first telnet immediatelly and the second telnet after sending out the message "this is a test".
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
int pid;
int sock;
void interrupt(int sig) {
close(sock);
if (pid) {
kill(pid, sig);
printf("Exiting...\n");
}
exit(0);
}
int main(int argc, char *argv[])
{
if (argc != 2) {
printf("Usage: %s portnumber\n", argv[0]);
return 1;
}
signal(SIGINT, &interrupt);
signal(SIGTERM, &interrupt);
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr = {
AF_INET,
htons(atoi(argv[1])),
INADDR_ANY
};
int res = bind( sock,
(struct sockaddr*)&addr,
sizeof(addr));
if (res < 0) {
perror("Bind");
return -1;
}
int pid = fork();
if (pid) {
while(1) {
char buf[100];
int chars = 0;
char c;
int portnumber;
scanf("%d", &portnumber);
struct sockaddr_in target = {
AF_INET,
htons(portnumber),
inet_addr("127.0.01")
};
while(read(0, &c, 1) > 0) {
if(c == '\n') {
// TODO send buf
sendto(sock, buf, chars, 0,
(struct sockaddr*)&target,
sizeof(target));
chars = 0;
break;
} else {
if (chars < 100)
buf[chars++] = c;
else
printf("\n->Maximum character is reached, press enter to send\n");
}
}
}
} else {
struct sockaddr_in incoming;
int lenincoming = sizeof(incoming);
char buf[101];
int chars = 0;
while( (chars = recvfrom(sock, &buf, 100, 0,
(struct sockaddr*)&incoming,
&lenincoming)) >= 0)
{
write(1, buf, chars);
write(1, "\n", 1);
buf[chars] = 0;
if (strcmp(buf, "ok") != 0) {
sendto( sock, "ok", 2, 0,
(struct sockaddr*)&incoming,
lenincoming);
}
}
}
return 0;
}
I want to modify this program so that a file can be sent. It should ask a port number and filename and then send the file in 100 byte packages to the other side. Every package should have starting point of the data. When I get data, I should seek to the location that is specified at the start of the data. Save to fixed filename or if you want transfer filename first. You can assume that you are working on the same system.
I read about "lseek(fd, start, SEEK_SET)". I think it should help. But how to combine it all?
I am writing a simple code to test thread pools. I have a client sendin lines of data to server through different ports.
Some threads receive the data, then send them to other threads for processing.
For now, the only processing I am doing is just to write the data into a file.
Here is the code of the worker thread.
void* worker_thread(void* arg){
int i, workerNum;
pthread_t worker_id = pthread_self();
char *ticket = (char*) arg;
char dumpfile[50];
for(i=0;i<10;i++)
if(pthread_equal(worker_id, id_pool[i]))
break;
if(10==i){
pthread_exit(NULL);
}
workerNum = i;
fprintf(stdout, "Worker [%d] busy\n",workerNum);
sprintf(dumpfile, "worker_%d.log",workerNum);
if(strlen(ticket)<4){
fprintf(stdout, "Worker [%d] RELEASED!!\n",workerNum);
poolStatus[workerNum] = 0;
pthread_mutex_unlock(&mutexes[workerNum]);
pthread_exit(NULL);
}
FILE *logFile = fopen(dumpfile, "a+");
// ticket[strlen(ticket)]
fprintf(logFile, "%s\n", ticket);
fclose(logFile);
sleep(workerNum+2);
poolStatus[workerNum] = 0;
fprintf(stdout, "Worker [%d] RELEASED!!\n",workerNum);
pthread_mutex_unlock(&mutexes[workerNum]);
pthread_exit(NULL);
}
The code works when I run through a debugger (GDB, under linux). When I run it simply on the command line, it runs but does not create the files!
Can you please assist?
the complete code:
#include <time.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <strings.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define BUFSIZE 65535
#define NUMWORKERS 10
static pthread_mutex_t mutexes[NUMWORKERS];
pthread_t id_pool[NUMWORKERS], id_servers[6];
int serverports[6] = {22191, 22192, 22193, 7525, 7526, 7527};
char poolStatus[NUMWORKERS] = {0};
void error(char *msg) {
FILE *logFile = fopen("errorlog.log", "a+");
fprintf(logFile, "%s\n", msg);
fclose(logFile);
exit(1);
}
void* serverListener(void* arg);
void* worker_thread(void* arg);
int main(){
int i, t_err[6];
for(i=0; i< NUMWORKERS; i++)
pthread_mutex_init(&mutexes[i],NULL);
for(i=0; i<6; i++){
t_err[i] = pthread_create(&id_servers[i], NULL, serverListener, NULL);
}
pthread_join(id_servers[5], NULL);
return 0;
}
void* serverListener(void* arg){
int parentfd, childfd; // parent socket & child socket
int portno, clientlen; // port number and size of client address
struct sockaddr_in serveraddr;
struct sockaddr_in clientaddr;// server and client addresses
struct hostent *hostp; // client host info
char buf[BUFSIZE]; // message buffer
char *hostaddrp; // dotted decimal host addr string
int optval, n; // flag value for setsockopt and message byte size
unsigned int CLOCKREF, CLOCKCOUNT;
pthread_t id = pthread_self(); // own thread id
int threadNumber, i=0; // thread number linked to ort to listen to.
char dumpfile[50];
for(i=0; i<6; i++) if(pthread_equal(id, id_servers[i])) break;
threadNumber = i;
portno = serverports[threadNumber];
sprintf(dumpfile, "receiver_%d.log",portno);
// socket: create the parent socket
parentfd = socket(AF_INET, SOCK_STREAM, 0);
if (parentfd < 0)
error("ERROR opening socket");
optval = 1;
setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int));
// build the server's Internet address
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
// let the system figure out our IP address
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
// this is the port we will listen on
serveraddr.sin_port = htons((unsigned short)portno);
// bind: associate the parent socket with a port
if (bind(parentfd, (struct sockaddr *) &serveraddr,
sizeof(serveraddr)) < 0)
error("ERROR on binding");
// listen: make this socket ready to accept connection requests
if (listen(parentfd, 5) < 0) /* allow 5 requests to queue up */
error("ERROR on listen");
// main loop: wait for a connection request
clientlen = sizeof(clientaddr);
while (1) {
// accept: wait for a connection request
childfd = accept(parentfd, (struct sockaddr *) &clientaddr, &clientlen);
if (childfd < 0)
error("ERROR on accept");
// gethostbyaddr: determine who sent the message
hostp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
sizeof(clientaddr.sin_addr.s_addr), AF_INET);
if (hostp == NULL)
error("ERROR on gethostbyaddr");
hostaddrp = inet_ntoa(clientaddr.sin_addr);
if (hostaddrp == NULL)
error("ERROR on inet_ntoa\n");
fprintf(stdout, "server established connection with %s (%s)\n", hostp->h_name, hostaddrp);
// read: read input string from the client
CLOCKREF = (unsigned int)time(NULL);
int counter = 0;
while(1){
CLOCKCOUNT = (unsigned int)time(NULL) - CLOCKREF;
bzero(buf, BUFSIZE);
n = read(childfd, buf, BUFSIZE);
if (n < 0) error("ERROR reading from socket");
if(0==n) counter++;
if(3<=counter) {
close(childfd);
return;
}
int busyWorker = 1;
i = 0;
while(busyWorker){
if(i>=NUMWORKERS) i = 0;
if(pthread_mutex_trylock(&mutexes[i])==0){ // not locked, can be used
fprintf(stdout, "port [%d] sends to thread [%d]\n", portno, i);
pthread_create(&id_pool[i], NULL, worker_thread, (void*)buf);
busyWorker = 0;
break;
}
i++;
}
}
close(childfd);
}
}
void* worker_thread(void* arg){
int i, workerNum;
pthread_t worker_id = pthread_self();
char *ticket = (char*) arg;
char dumpfile[50];
for(i=0;i<10;i++)
if(pthread_equal(worker_id, id_pool[i]))
break;
if(10==i){
pthread_exit(NULL);
}
workerNum = i;
fprintf(stdout, "Worker [%d] busy\n",workerNum);
sprintf(dumpfile, "worker_%d.log",workerNum);
if(strlen(ticket)<4){
fprintf(stdout, "Worker [%d] RELEASED!!\n",workerNum);
poolStatus[workerNum] = 0;
pthread_mutex_unlock(&mutexes[workerNum]);
pthread_exit(NULL);
}
FILE *logFile = fopen(dumpfile, "a+");
// ticket[strlen(ticket)]
fprintf(logFile, "%s\n", ticket);
fclose(logFile);
sleep(workerNum+2);
poolStatus[workerNum] = 0;
fprintf(stdout, "Worker [%d] RELEASED!!\n",workerNum);
pthread_mutex_unlock(&mutexes[workerNum]);
pthread_exit(NULL);
}
I believe I have found the problem!!
To pass a message from serverListener thread to worker_thread, I used the pointer to buffer used to read from the socket. Problem is, before the worker_thread could process it, the serverListener has reset the value to zero ( bzero(buf, BUFSIZE) ) ! and given the fact that the worker_thread must only write to file when the size is greater than 4, it doesn't write it.
so to solve my problem, I replaced the line:
pthread_create(&id_pool[i], NULL, worker_thread, (void*)buf);
by:
char *msg2send = strdup(buf);
pthread_create(&id_pool[i], NULL, worker_thread, (void*)msg2send);
And it did the trick!!
Still does not really explain why it could create the files in debug mode though...
I've made a message queue for my fileserver (runs on linux) and it all seems to go well when I upload (from windows client) a file to the the server through the client. Once the file is uploaded though I get all these vague symbols on the serverside.
I've got the following code on the client side
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stddef.h>
#include "mailbox.h"
#define MAXCLIENTS 5
#define PORTNR 5002
#define MAXUSERS 1024
/*
int inet_aton(const char *cp, struct in_addr *inp);
char *inet_ntoa(struct in_addr in);
void *memset(void *s, int c, size_t n);
int close(int fd);
*/
//Prototyping van de functies
void *childThread(void *ad);
void uploadFile(int nsockfd);
void downloadFile(int nsockfd);
void establishConnection();
int login(char *username, char *password);
int get_queue_ds( int qid, struct msqid_ds *qbuf);
int change_queue_mode(int qid, char *mode);
//Upload files= 0, Download files= 1
int serverState = 0;
int numberLoggedInUsers = 0;
struct sockaddr_in client; // Struct for Server addr
struct message req;
struct msqid_ds mq_id = {0};
int clientUpload;
ssize_t msgLen;
char *username;
char *password;
int main(int argc, char** argv) {
// create message queue key
key_t key;
if((key = ftok("/home/MtFS/Iteraties/ftokDing", 13)) < 0) {
perror("ftok");
exit(1);
}
// create queue, if not succesfull, remove old queue
// and try to make a new one.
while ((clientUpload = msgget(key, 0666 | IPC_CREAT| IPC_EXCL)) < 0) { //| S_IRGRP | S_IWUSR
perror("msgget");
// delete message queue if it exists
if (msgctl(clientUpload, IPC_RMID, &mq_id) == -1) {
perror("msgctl1");
exit(1);
}
}
change_queue_mode(clientUpload, "0666");
/*
if (msgctl(clientUpload, IPC_STAT, &mq_id) == -1) {
perror("msgctl2");
exit(1);
}
if (msgctl(clientUpload, IPC_SET, &mq_id) == -1) {
perror("msgctl3");
exit(1);
}
*/
establishConnection();
return 0;
}
int get_queue_ds(int qid, struct msqid_ds *qbuf) {
if (msgctl(qid, IPC_STAT, qbuf) == -1) {
perror("msgctl IPC_STAT");
exit(1);
}
return 0;
}
int change_queue_mode(int qid, char *mode) {
struct msqid_ds tmpbuf;
/* Retrieve a current copy of the internal data structure */
get_queue_ds(qid, &tmpbuf);
/* Change the permissions using an old trick */
sscanf(mode, "%ho", &tmpbuf.msg_perm.mode);
/* Update the internal data structure */
if (msgctl(qid, IPC_SET, &tmpbuf) == -1) {
perror("msgctl IPC_SET");
exit(1);
}
return (0);
}
void establishConnection() {
pthread_t child; //Thread ID of created thread
int sockfd; //Integer for socket
int nsockfd; //Integer for client socket
socklen_t sizeAddr; //Length of socket
struct sockaddr_in addr; //Struct for client addr
int optValue = 1; //Int for setsockoptions
char ipAdres[32] = "192.168.80.2"; //IP-adres of server
sizeAddr = sizeof (struct sockaddr_in);
// create socket and errorhandling if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("[socket()]");
exit(1);
} else {
printf("================================================================\n\n");
printf("Socket created succesfully.\n\n");
}
// Fill socket with portno and ip address
addr.sin_family = AF_INET; // Protocol Family
addr.sin_port = htons(PORTNR); // Portnumber
inet_aton(ipAdres, &addr.sin_addr); // Local IP- adres
bzero(&(addr.sin_zero), 8); // empty rest of struct
// int setsockopt (int fd, int level, int optname, const void *optval, socklen_t optlen)
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optValue, sizeof (int)) == -1) {
perror("[setsockopt()]");
exit(1);
}
// Fil socket with portnr and ip adress, also implemented error handling
if (bind(sockfd, (struct sockaddr*) &addr, sizeof (struct sockaddr)) == -1) {
perror("[bind()]");
exit(1);
} else {
printf("================================================================\n\n");
printf("Portnr %d is succesfully connected %s to.\n\n", PORTNR, ipAdres);
}
// Listen to incoming connections and errorhandling
if (listen(sockfd, MAXCLIENTS) == -1) {
perror("[listen()]");
exit(1);
} else {
printf("================================================================\n\n");
printf("Listen to port %d successfull.\n\n", PORTNR);
}
//Connectionloop to process connection requests from clients
while (1) {
//Accept incoming clients with error handling.
if ((nsockfd = accept(sockfd, (struct sockaddr *) &client, &sizeAddr)) == -1) {
perror("[accept()]");
exit(1);
} else {
//create child thread
pthread_create(&child, NULL, childThread, (void *) nsockfd);
/*
// wait untill other child is ready
pthread_join(child, &status);
*/
}
}
}
void *childThread(void *nsockfd) {
int sizeReceivedFile = 0;
char receiveBuffer[PACKETSIZE]; //Buffer voor de ontvangen bestanden
//char sendBuffer[PACKETSIZE]; //Buffer voor de te zenden bestanden
//int sizeSendFile = 0; //Grootte van het te zenden bestand
//char yolocol[PACKETSIZE];
char *clientRequest; //Char pointer voor het type request client, permissie en bestandsnaam
int loginStatus = 0; // 0 = uitgelogd, 1 = ingelogd
char *loggedInAs;
printf("================================================================\n\n");
printf("Connected with a client on IP-Adres: %s.\n\n", inet_ntoa(client.sin_addr));
bzero(receiveBuffer, PACKETSIZE);
while ((sizeReceivedFile = recv((int) nsockfd, receiveBuffer, PACKETSIZE, 0)) > 0) {
// receive from client
printf("Ontvangen buffer: %s\n",receiveBuffer);
if (sizeReceivedFile == 0) {
break;
}
// flags
// retreive flag with strtok
clientRequest = strtok(receiveBuffer, "#");
printf("packet type: %s\n", clientRequest);
// 2 = list
// 3 = download
// 4 = upload
// 5 = login
// 6 = logout
if (strcmp(clientRequest, "2") == 0) {
printf("execute list on current directory!\n");
} else if (strcmp(clientRequest, "3") == 0) {
downloadFile((int) nsockfd);
} else if (strcmp(clientRequest, "4") == 0) {
uploadFile((int) nsockfd);
} else if (strcmp(clientRequest, "5") == 0){
username = strtok(NULL,"#");
password = strtok(NULL,"#");
printf("Username = %s \n password = %s \n",username,password);
int test;
if((test= login(username,password))== 1){
printf("login success, %i\n", test);
loginStatus = 1;
}
else{
printf("Inloggen mislukt, %i\n", test);
loginStatus = 0;
}
} else if (strcmp(clientRequest, "6")== 0) {
loginStatus = 0;
printf("%s logged out\n", loggedInAs);
loggedInAs = "";
}
}
return 0;
}
void uploadFile(int nsockfd) {
/*
printf("execute download!\n");
fileToDownload = strtok(NULL,"#");
printf("%s",fileToDownload);
int sizeReceivedFile = 0;
// if relcv() returns 0 then the connection is gone
while (sizeReceivedFile != 0) {
//Upload of files
if (serverState == 0) {
sizeReceivedFile = recv((int) nsockfd, req.pakket.buffer, PACKETSIZE, 0);
if (sizeReceivedFile < 0) {
perror("[receive()]");
exit(0);
} else if (sizeReceivedFile == 0) {
printf("The client has dropped the connection \n");
close((int) nsockfd);
pthread_exit(NULL);
}
// put the packet in the mailbox
req.mtype = RESP_MT_DATA; // has to be positive
req.pakket.clientID = clientUpload;
if (msgsnd(clientUpload, &req, PACKETSIZE, 0) == -1) {
perror("msgsnd");
}
}
}
req.mtype = RESP_MT_END;
msgsnd(clientUpload, &req, 0, 0);
close((int) nsockfd);
printf("================================================================\n\n");
printf("Connection with client has been lost. Server is waiting for new clients clients...\n\n");
}
void downloadFile(int nsockfd) {
/*
printf("execute download!\n");
fileToDownload = strtok(NULL,"#");
printf("%s",fileToDownload);
*/
char sendBuffer[PACKETSIZE];
int sizeSendFile = 0;
if (send((int) nsockfd, sendBuffer, sizeSendFile, 0) < 0) {
perror("[send()]");
//exit(1);
}
bzero(sendBuffer, PACKETSIZE);
}
And this is the server side. I made one process for handling the connection, which transfers all incoming packets that say 'upload' in one of my custom made protocol flags to a message queue. This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stddef.h>
#include "mailbox.h" // self made header file
#define MAXCLIENTS 5
#define PORT 5002
#define MAXUSERS 1024
//Prototyping
void *childThread(void *ad);
void uploadFile(int nSockfd);
void buildConnection();
int get_queue_ds( int qid, struct msqid_ds *qbuf);
int change_queue_mode(int qid, char *mode);
// Upload files= 0, Download files= 1
int serverState = 0;
struct sockaddr_in client;
struct bericht req;
struct msqid_ds mq_id = {0};
int messageQueue;
ssize_t msgLen;
int main(int argc, char** argv) {
// message queue key aanmaken
key_t key;
if((key = ftok("/home/file", 13)) < 0) {
perror("ftok");
exit(1);
}
// queue aanmaken, als dit niet lukt de eventueel oude queue verwijderen
// en queue opnieuw proberen aan te maken.
while ((messageQueue = msgget(key, 0666 | IPC_CREAT| IPC_EXCL)) < 0) {
perror("msgget");
// message queue verwijderen als deze al bestaat
if (msgctl(messageQueue, IPC_RMID, &mq_id) == -1) {
perror("msgctl1");
exit(1);
}
}
change_queue_mode(messageQueue, "0666");
buildConnection();
return 0;
}
int get_queue_ds(int qid, struct msqid_ds *qbuf) {
if (msgctl(qid, IPC_STAT, qbuf) == -1) {
perror("msgctl IPC_STAT");
exit(1);
}
return 0;
}
int change_queue_mode(int qid, char *mode) {
struct msqid_ds tmpbuf;
// Retrieve a current copy of the internal data structure
get_queue_ds(qid, &tmpbuf);
// Change the permissions using an old trick
sscanf(mode, "%ho", &tmpbuf.msg_perm.mode);
// Update the internal data structure
if (msgctl(qid, IPC_SET, &tmpbuf) == -1) {
perror("msgctl IPC_SET");
exit(1);
}
return (0);
}
void buildConnection() {
pthread_t child;
int sockfd;
int nSockfd;
socklen_t sockaddrSize;
struct sockaddr_in addr;
int optValue = 1;
char ipAdres[32] = "192.168.80.2";
sockaddrSize = sizeof (struct sockaddr_in);
// create socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("[socket()]");
exit(1);
} else {
printf("================================================================\n\n");
printf("Socket is succesfully created.\n\n");
}
// fill dat socket
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
inet_aton(ipAdres, &addr.sin_addr);
bzero(&(addr.sin_zero), 8);
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optValue, sizeof (int)) == -1) {
perror("[setsockopt()]");
exit(1);
}
if (bind(sockfd, (struct sockaddr*) &addr, sizeof (struct sockaddr)) == -1) {
perror("[bind()]");
exit(1);
} else {
printf("================================================================\n\n");
printf("bind succesful");
}
if (listen(sockfd, MAXCLIENTS) == -1) {
perror("[listen()]");
exit(1);
} else {
printf("================================================================\n\n");
printf("Listening on port %d\n\n", PORT);
}
// Connection loop
while (1) {
// accept incoming clients
if ((nSockfd = accept(sockfd, (struct sockaddr *) &client, &sockaddrSize)) == -1) {
perror("[accept()]");
exit(1);
} else {
pthread_create(&child, NULL, childThread, (void *) nSockfd);
}
}
}
void *childThread(void *nSockfd) {
int sizeOfRecvFile = 0;
char recvBuffer[PACKETSIZE];
char *clientCommand; // request type
printf("================================================================\n\n");
printf("connected to client with IP: %s.\n\n", inet_ntoa(client.sin_addr));
bzero(recvBuffer, PACKETSIZE);
// get dem datas
while ((sizeOfRecvFile = recv((int) nSockfd, recvBuffer, PACKETSIZE, 0)) > 0) {
if (sizeOfRecvFile == 0) {
break;
}
printf("received buffer: %s\n", recvBuffer);
// handle protocol flag
// chop protocol into pieces to check packet data and flags
clientCommand = strtok(recvBuffer, "#");
printf("packet type: %s\n", clientCommand);
// if clientCommand == 4
// incoming file!
if (strcmp(clientCommand, "4") == 0) {
uploadFile((int) nSockfd);
}
}
return 0;
}
void uploadFile(int nSockfd) {
int sizeOfRecvFile = 0;
// if recv() is 0 close connection
while (sizeOfRecvFile != 0) {
if (serverStaat == 0) {
sizeOfRecvFile = recv((int) nSockfd, req.pakket.buffer, PACKETSIZE, 0);
if (sizeOfRecvFile < 0) {
perror("[receive()]");
exit(0);
} else if (sizeOfRecvFile == 0) {
printf("Client disconnected\n");
close((int) nSockfd);
pthread_exit(NULL);
}
// send packet to message queue
req.mtype = RESP_MT_DATA;
req.pakket.clientID = messageQueue;
if (msgsnd(messageQueue, &req, PACKETSIZE, 0) == -1) {
perror("msgsnd");
}
}
}
req.mtype = RESP_MT_END;
msgsnd(messageQueue, &req, 0, 0);
close((int) nSockfd);
printf("================================================================\n\n");
printf("Disconnected, now waiting for other clients...\n\n");
}
The above program uses a custom made header file:
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <stddef.h>
#include <limits.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#define PACKETSIZE 65535
struct message {
long mtype;
struct packet {
int clientID;
char buffer[PACKETSIZE];
} packet;
};
#define REQ_MSG_SIZE (offsetof(struct message.pakket, buffer) - \
offsetof(struct message.pakket, clientID) - PACKETSIZE)
struct responseMsg { // Responses (server to client)
long mtype; // One of RESP_MT_* values below
char data[PACKETSIZE]; // File content / response message
};
// Types for response messages sent from server to client
#define RESP_MT_FAILURE 1 // File couldn't be opened
#define RESP_MT_DATA 2 // Message contains file data
#define RESP_MT_END 3 // File data complete
I also made a process which writes the uploaded files to the hdd. This process gets data from the message queue that was created in the connection process. The code:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include "/home/CommProces/mailbox.h"
#define POORTNR 5002
#define MAXCLIENTS 5
// prototyping
void writeFiles();
struct message resp;
int uploadMessage;
ssize_t msgLen;
int main () {
key_t key;
if(key = ftok("/home/CommProces/ftokDing", 13) < 0) {
perror("ftok");
exit(1);
}
uploadMessage = msgget(key, 0666);
if (uploadMessage == -1) {
perror("msgget");
exit(1);
}
while(1) {
writeFiles();
}
}
void writeFiles() {
char recvBuffer[PACKETSIZE];
char *rights, *pathname, *filename, *temp;
char *pathOfRecvFile; // received files will go here
FILE* theFile;
bzero(recvBuffer, PACKETSIZE);
int numMsgs, totBytes;
int sizeOfRecvFile = 0;
int nBytesToDisk = 0;
totBytes = msgLen; // Count first message
for (numMsgs = 1; resp.mtype == RESP_MT_DATA; numMsgs++) {
msgLen = msgrcv(uploadMessage, &resp, PACKETSIZE, 0, 0);
if (msgLen == -1) {
perror("msgrcv");
totBytes += msgLen;
}
*recvBuffer = *resp.pakket.buffer;
//temp = strtok(recvBuffer,"#");
rights = strtok(NULL,"#");
if(strcmp(rights, "private") == 0) {
temp = strtok(NULL,"#");
pathname = strcat("/home/MtFS/UploadedFiles/private/", temp);
} else {
pathname = "/home/MtFS/UploadedFiles/public";
}
filename = strcat("/", strtok(NULL,"#"));
pathOfRecvFile = strcat(filename, pathname);
theFile = fopen(pathOfRecvFile, "wb");
if(theFile == NULL) {
printf("[Open_File] unable to create file %s\n", pathOfRecvFile);
} else {
nBytesToDisk = fwrite(recvBuffer, sizeof(char), sizeOfRecvFile, theFile);
if(nBytesToDisk < sizeOfRecvFile) {
perror("fwrite");
}
printf("=============================================================================================================================\n\n");
printf("Files received and placed on HDD\n\n");
bzero(recvBuffer, PACKETSIZE);
}
if (resp.mtype == RESP_MT_FAILURE) {
printf("mtype = fail");
} else if(resp.mtype == RESP_MT_END) {
printf("mtype = end of data");
fclose(theFile);
}
}
}
I've been sifting through breakpoints with the debugger but I can't lay my finger on what's causing the problem :(
For starters, the 3rd parameter to msgrcv() gives the size of the message's payload.
So this line
msgLen = msgrcv(uploadMessage, &resp, PACKETSIZE, 0, 0);
should be
msgLen = msgrcv(uploadMessage, &resp, sizeof(resp)-sizeof(resp.mtype), 0, 0);
or
msgLen = msgrcv(uploadMessage, &resp, sizeof(resp.packet), 0, 0);
Also calling strtok() with the 1st argument set to NULL, does not make sense. It initialy needs to be called with the 1st agrment pointing to some 0 -terminated char-array.
Also^2: Trying to concatenate to a string literal uinsg strcat() like here:
pathname = strcat("/home/MtFS/UploadedFiles/private/", temp);
invokes undefined behaviour.
To fix this make pathname a buffer, instead of a pointer:
char pathname[PATHMAX] = "";
...
if(strcmp(rights, "private") == 0) {
temp = strtok(NULL,"#");
strcpy(pathname, "/home/MtFS/UploadedFiles/private/");
strcat(pathname, temp);
} else {
strcpy(pathname, "/home/MtFS/UploadedFiles/public");
}
The code you posted is describing a non-trivial system, involving a tcp-to-mq proxy (the client) and a mq-server. I strongly advise to debug those compoments separately.
There are some strange things happening in my client-server application. Please, look at these simple fork client/server:
CLIENT:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/wait.h>
#define IP_SERVER "192.168.1.89"
#define PORT_SERVER 65000
#define BUFFERSIZE 1024
#define NUMFILES 3
double timeElapsed(struct timeval* before, struct timeval* after) {
return after->tv_sec - before->tv_sec + (double) (after->tv_usec - before->tv_usec)/1000000;
}
void getFile(char *request, struct sockaddr_in server) {
char buffer[1024];
int sockProc, res;
int file;
int sizeServ = sizeof(server);
int writeFile;
sockProc = socket(AF_INET, SOCK_STREAM, 0);
if (sockProc < 0) {
printf("Error on creating socket client\n");
perror("");
exit(1);
}
file = open(request, O_CREAT | O_WRONLY, S_IRWXU);
res = connect(sockProc, (struct sockaddr*)&server, (socklen_t)sizeServ);
if (res < 0) {
printf("Error on connecting to server!\n");
perror("");
exit(1);
}
res = send(sockProc, (void*)request, strlen(request), 0);
memset(buffer, 0, sizeof(buffer));
while((res = recv(sockProc, (void*)buffer, sizeof(buffer), 0)) > 0) {
write(file, (void*)buffer, strlen(buffer));
memset(buffer, 0, sizeof(buffer));
}
close(sockProc);
close(file);
return;
}
int main(int argc, char** argv) {
int sockCli, res, i;
struct sockaddr_in server;
int sizeServ = sizeof(server);
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
inet_pton(AF_INET, IP_SERVER, &server.sin_addr);
server.sin_port = htons(PORT_SERVER);
char files[NUMFILES][32];
char nameFile[32];
char command[32] = "rm *.txt";
system(command);
struct timeval begin;
struct timeval end;
pid_t processes[NUMFILES];
for(i = 0; i<NUMFILES; i++) {
memset(nameFile, 0, sizeof(nameFile));
printf("Inserisci nome file (con estensione) da ricevere:\n");
scanf("%s", nameFile);
strcpy(files[i], nameFile);
}
gettimeofday(&begin, NULL);
for(i=0; i<NUMFILES; i++) {
pid_t child = fork();
if(child == 0) {
getFile(files[i], server);
exit(0);
}
else {
processes[i] = child;
continue;
}
}
/*for(i=0; i<NUMFILES; i++) {
waitpid(processes[i], NULL, 0);
}*/
wait(NULL);
gettimeofday(&end, NULL);
printf("Time elapsed on TCP is %f seconds\n", timeElapsed(&begin, &end));
return 0;
}
and the SERVER:
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#define IP_SERVER "192.168.1.89"
#define PORT_SERVER 65000
#define BUFFERSIZE 1024
void execRequest(int* sockCli, struct sockaddr_in* client) {
char buffer[BUFFERSIZE];
char request[BUFFERSIZE];
int res;
memset(request, 0, sizeof(request));
res = recv(*sockCli, (void*)request, sizeof(request), 0);
if(res < 0) {
printf("Error on recv()\n");
perror("");
exit(1);
}
printf("Requested file %s\n", request);
char resource[32] = "files/";
strcat(resource, request);
int file = open(resource, O_RDONLY);
if (file < 0) {
printf("File %s does not exist\n", request);
exit(1);
}
memset(buffer, 0, sizeof(buffer));
while((res = read(file, (void*)buffer, sizeof(buffer))) > 0) {
send(*sockCli, (void*)buffer, strlen(buffer), 0);
memset(buffer, 0, sizeof(buffer));
}
close((*sockCli));
close(file);
free(sockCli);
free(client);
return;
}
int main(int argc, char** argv) {
int sockServ, i, res;
int *sockCli;
struct sockaddr_in server;
struct sockaddr_in* client;
sockServ = socket(AF_INET, SOCK_STREAM, 0);
if(sockServ < 0) {
printf("Error in creating socket\n");
perror("");
exit(1);
}
memset(&server, 0, sizeof(server));
server.sin_addr.s_addr = inet_addr(IP_SERVER);
server.sin_port = htons(PORT_SERVER);
server.sin_family = AF_INET;
int reuse = 1;
res = setsockopt(sockServ, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
if (res < 0) {
printf("setsockopt() REUSEADDR failed\n");
perror("");
exit(1);
}
res = bind(sockServ, (struct sockaddr*)&server, sizeof(server));
if (res < 0) {
printf("Error on bindind TCP server!\n");
perror("");
exit(1);
}
res = listen(sockServ, 5);
if (res < 0) {
printf("Error on listening TCP server!\n");
perror("");
exit(1);
}
while(1) {
sockCli = (int*)malloc(sizeof(int));
client = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
int sizeClient = sizeof(struct sockaddr_in);
*sockCli = accept(sockServ, (struct sockaddr*)client, &sizeClient);
if ((*sockCli) < 0) {
printf("accept() failed\n");
perror("");
continue;
}
printf("Connected to %s:%d\n", inet_ntoa(client->sin_addr), client->sin_port);
if( !fork() ) {
execRequest(sockCli, client);
exit(0);
}
else
continue;
}
return 0;
}
This is very strange. The processes created by the client don't terminate even if the server closes the sockets and so recv() should return 0 and let client processes exit from the loop. Moreover there's something strange about reading files:
the server simply reads files.txt but in doing this it includes the string ".txt" in the read characters and sends all this mixture to the client...why?
they are simple file mono character like
aaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaa
but the server reads and and sends:
aaaaaaaaaaaaaaaaaa.txt
aaaaaaaaaaaaaaaaaa
can I solve all this?
You can't use strlen(buffer), just because you're loading characters from a text file doesn't mean that buffer will be a valid string unless you take steps to ensure it is. And you don't; there's no termination since you can fill all of buffer with data from the file.
How many times must we play the broken record here on Stack Overflow? Don't cast malloc!
I chalk this error to failure to read the manual(s), to find out what header to include, what a string is (and hence what strlen/strcat/str*{anything}* expects of its input, what printf expects of arguments that correspond to a %s format specifier, etc.) and what read/recv produces.
res = recv(*sockCli, (void*)request, sizeof(request), 0);
if(res < 0) {
printf("Error on recv()\n");
perror("");
exit(1);
}
printf("Requested file %.*s\n", res, request); // NOTE the field width provided by 'res'
By the manual, examples such as res = read(file, (void*)buffer, sizeof(buffer)) supposedly store either an error or a length. The condition ensures that the send code will only execute when it's a length value, so why not use it as one? send(*sockCli, (void*)buffer, res, 0);?
The presense of these problems seems to indicate that your method of learning isn't working. Which book are you reading? Learning C without a book is a bit like learning which berries are poisonous without communication.