server stops creating threads - c

I have a very simple client-server code. Every time a server receives a packet I create a thread that handles it. The code is shown below. What I can't understand is that after sometime my server stops receiving any data. It just listens and doesn't receive anything. I can't figure out why. Does anyone know the reason.
I'm building my code on Lenovo T470s Fedora 29, Linux user 4.19.15-300.fc29.x86_64 #1 SMP Mon Jan 14 16:32:35 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
Any help is appreciated.
/*
server.c
cc -std=gnu11 -pedantic -lpthread server.c -o server.c
*/
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <poll.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUF_SIZE_B 1024
static int fd;
static void *handlePacketThreadWrapper(void *arg);
int main(void)
{
pthread_t t;
struct pollfd pollfd;
struct sockaddr_in addr;
uint16_t port = 9500;
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (fd < 0)
{
printf("errno: %d. %s. Failed to create a socket",
errno, strerror(errno));
exit(EXIT_FAILURE);
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
while(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
printf("errno: %d. %s. Failed to bind socket. Will attempt again.", errno,
strerror(errno));
sleep(1);
}
memset(&addr, 0, sizeof(addr));
pollfd.fd = fd;
pollfd.events = POLLIN;
while(true)
{
if (poll(&pollfd, 1, -1) < 0)
{
printf("errno: %d. %s", errno, strerror(errno));
}
else
{
pthread_create(&t, NULL, handlePacketThreadWrapper, NULL);
}
}
return 0;
}
static void *handlePacketThreadWrapper(void *arg)
{
uint8_t buf[BUF_SIZE_B];
size_t strLen, fullIPLen;
ssize_t
i,
n
;
struct sockaddr_in addr;
socklen_t addrLen = sizeof(addr);
char *str, *fullIP;
n = recvfrom(fd, buf, sizeof(buf), 0,
(struct sockaddr *)&addr, (socklen_t *)&addrLen);
if (n < 0)
{
printf("errno: %d. %s. Failed to create a socket",
errno, strerror(errno));
}
else
{
for (i = 0; i < n; i++)
{
printf("0x%02X ", buf[i]);
}
printf("\n");
}
return NULL;
}
And here is my client code:
/*
client.c
cc -std=gnu11 -pedantic client.c -o client.c
*/
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#define BUF_SIZE_B 1024
int main(void)
{
ssize_t size, i;
struct sockaddr_in dest;
int fd;
char *toIP = "127.0.0.1";
uint16_t toPort = 9500;
uint8_t buf[BUF_SIZE_B];
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (fd < 0)
{
printf("errno: %d, %s", errno, strerror(errno));
exit(EXIT_FAILURE);
}
memset(&dest, 0, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr(toIP);
dest.sin_port = htons(toPort);
while(true)
{
size = sendto(fd, buf, sizeof(buf), 0, (struct sockaddr*)&dest, sizeof(dest));
if (size < 0)
{
printf("errno: %d. %s. Failed to send bytes to %s:%hu.",
errno, strerror(errno), toIP, toPort);
}
else
{
for (i = 0; i < size; i++)
printf("0x%02X ", buf[i]);
printf("\n");
}
usleep(1000);
}
return 0;
}

You can only have as many threads running simultaneously, as ulimit -u reports.
Your server never joins the threads, and once the limit is reached it starts failing to create them.

In your server the main thread and the created thread(s) access the same socket (fd) without any protection like exclusive section, so the execution of poll and recvfrom can be done in any order including simultaneously, that probably destruct the internal data of the socket.
You can do for example :
while(true)
{
if (poll(&pollfd, 1, -1) < 0)
{
printf("errno: %d. %s", errno, strerror(errno));
}
else
{
pthread_create(&t, NULL, handlePacketThreadWrapper, NULL);
pthread_join(&t);
}
}
That both protect the use of the socket and avoid zombie thread as mentioned by user58697 in an other answer (the threads are not detached by default).
Of course doing that limit the interest to read on the socket in an other thread, but your code is not really compatible with multi threading for several reasons

Related

SIGIO never fires

ioctl() with changes a socket to asynchronous mode. By the definition on the man page, the kernel sends SIGIO when i/o is possible on the socket. I've run this with test clients and i/o is fine (packets arrive at source and destination), so why wouldn't the kernel call sigpoll?
To clarify, the problem is that despite having established the SIGIO signal and appropriating the socket to send the signal SIGIO, no signal ever fires or there is no indication that sigpoll() was called.
I've uploaded the code where I've found this issue, it will eventually be some watered down version of talk.
talkish.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <setjmp.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>
#define MAX_BUF 1000
#define CHAR_BUF 50
#define BASEPORT "10000"
void error(const char *msg){
perror(msg);
exit(1);
}
typedef struct tuple{
char HN [MAX_BUF];
char PN [MAX_BUF];
}tuple;
tuple storeCMD( char input[]){
tuple ret;
char* token = strtok(input, " ");
if (token != NULL) strcpy( ret.HN, token);
else ret.HN[0] = 0;
token = strtok(NULL, " ");
if (token != NULL) strcpy( ret.PN, token);
else ret.PN[0] = 0;
return ret;
}
void sigpoll(int sig){
printf("Signal fired!\n");
//eventual rcvfrom and other things...
}
int main(int argc, char * argv[]){
if (argc != 2){
printf("Proper usage requires 2 arguments: $talkish port-number\n");
exit(1);
}
int sd;
struct sockaddr_storage client;
socklen_t clientLen;
struct addrinfo server, *res;
struct addrinfo *serverinfo;
char buffer [MAX_BUF];
memset(&server, 0, sizeof(server));
bzero((char *) &server, sizeof(server));
server.ai_family = AF_INET;
server.ai_socktype = SOCK_DGRAM;
server.ai_flags = AI_PASSIVE;
//initially we'll use information from user, but move to partner and partnerl
//once solid connection is established.
struct sockaddr_storage partner;
socklen_t partnerl;
//Bind to argv[1]
tuple execute;
getaddrinfo(NULL, argv[1], &server, &res);
sd = socket(res -> ai_family ,res -> ai_socktype, res -> ai_protocol);
if (sd < 0) error("ERROR on socket!");
int n = bind(sd, res -> ai_addr, res -> ai_addrlen);
if (n < 0) error("ERROR on Bind!");
int flag;
flag= 1;
fcntl(sd, F_SETOWN, getpid());
signal(SIGPOLL, sigpoll); //establish sigpoll to get udp packets
ioctl(sd, FIOASYNC, &flag);
//establish timer to allow wait and see
struct timeval timer;
timer.tv_sec = 7;
//while connecting
char message[CHAR_BUF];
bzero((char *) message, CHAR_BUF);
int connecting = 1;
while(connecting){
printf ("? ");
scanf(" %[^\n]", message);
if (strlen(message) == 0);
else if ( 0 == strcmp( message, "q")){
exit (0);
}
else {
execute = storeCMD(message);
if (execute.HN[0] == 0 || execute.PN[0] == 0) printf("| Input should match \"Hostname Portname\" to connect and \"q\" to quit \n");
else {
struct sockaddr_storage dest_server;
socklen_t dest_serverl;
struct addrinfo dest_hints, *dest_res;
struct in_addr dest_addr;
memset(&dest_hints, 0, sizeof(dest_hints));
dest_hints.ai_family = AF_INET;
dest_hints.ai_socktype = SOCK_DGRAM;
dest_hints.ai_flags = AI_PASSIVE;
if (getaddrinfo( execute.HN, execute.PN, &dest_hints, &dest_res) < 0) printf("| Input should match \"Hostname Portname\" to connect and \"q\" to quit \n");
else {
bzero((char *) buffer, MAX_BUF);
sprintf(buffer, "wannachat");
sendto(sd, buffer, MAX_BUF, 0, (struct sockaddr *) dest_res -> ai_addr, dest_res -> ai_addrlen );
if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &timer, sizeof(timer)) < 0) error("ERROR on setsockopt");
partnerl = sizeof(partner);
bzero((char *) &partner, partnerl);
bzero((char *) buffer, MAX_BUF);
if (recvfrom(sd, buffer, MAX_BUF, 0, (struct sockaddr *)&partner, &partnerl ) < 0) printf("| No response received from %s. \n", execute.HN);
else{
if ( 0 == strcmp( buffer, "OK")){
printf("| Connected to %s. \n", execute.HN);
//chat();
}else printf("| %s does not want to talk. \n", execute.HN);
}
}
}
}
}
close(sd);
return 0;
}
To receive SIGIO notifications (also SIGURG for sockets, e.g: when receiving TCP URG data), you'll need to tell the kernel who to notify, using fcntl(fd, F_SETOWN, pid). As usual, a positive pid value refers to a process, while a negative pid refers to a process group.
On Linux, if you want to send the signal to a specific thread, you'll need to use F_SETOWN_EX. On other systems, you'll have to block the signal on other threads. using pthread_sigmask().

writing to a close socket didn't raise a SIGPIPE as expected

I've already read about how to prevent SIGPIPE, then I write a small program to test it. Here is the code.
server.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void hdl(int sig_num, siginfo_t *sig_info, void *context)
{
printf("got you, SIGPIPE!\n");
}
int main()
{
int sfd, cfd;
struct sockaddr_in saddr, caddr;
struct sigaction act;
memset (&act, '\0', sizeof(act));
act.sa_sigaction = hdl;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGPIPE, &act, NULL) < 0) {
return 1;
}
sfd= socket(AF_INET, SOCK_STREAM, 0);
saddr.sin_family=AF_INET;
saddr.sin_addr.s_addr=inet_addr("192.168.22.91");
saddr.sin_port=htons(12345);
if(bind(sfd, (struct sockaddr *)&saddr, sizeof(saddr)) )
{
printf("bind error\n");
return -1;
}
if(listen(sfd, 1))
{
printf("error\n");
return -1;
}
char buf[1024] = {0};
while(1) {
printf("Server listening...\n");
cfd=accept(sfd, (struct sockaddr *)NULL, NULL);
fcntl(cfd, F_SETFL, O_NONBLOCK);
int size = read(cfd, buf, 1024);
if(size == -1)
printf("read error\n");
sleep(2); // sleep for a while to make sure the client closed the socket
int ret;
if((ret = write(cfd, buf, strlen(buf)))<0)
{
if(errno == EPIPE)
fprintf(stderr, "SIGPIPE");
}
ret = write(cfd, buf, strlen(buf)); // write again.
printf("write return %d\n", ret);
}
close(sfd);
}
client.c
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <assert.h>
int main()
{
int ret, fd;
struct sockaddr_in sa_dst;
char buffer[] = "hello, world";
char rcv_buf[128] = {0};
fd = socket(AF_INET, SOCK_STREAM, 0);
memset(&sa_dst, 0, sizeof(struct sockaddr_in));
sa_dst.sin_family = AF_INET;
sa_dst.sin_port = htons(12345);
sa_dst.sin_addr.s_addr = inet_addr("192.168.22.91");
ret = connect(fd, (struct sockaddr *)&sa_dst, sizeof(struct sockaddr));
if(ret != -1)
{
send(fd, buffer, strlen(buffer), 0);
close(fd);
}
return 0;
}
When I run the server and the client on the same linux machine, on the server side, the first write() returns the number of bytes written while I expect a SIGPIPE signal because I closed the socket on the client side, the second write() does generate a SIGPIPE signal.
But when I ran the client on another linux machine or on a Windows machine(implement the same client with Winsock), I did't catch any SIGPIPE signal, and the second write() still returns the size of the buffer. Can someone tell me what's going on?
It can't happen on the first write, for two reasons:
The localhost doesn't know that the peer has closed the socket for reading. A FIN has been received but that could just be because the peer has shutdown for output. Only an RST will tell it that, and it doesn't get that util the next I/O at the earliest.
Buffering.
NB you're corrupting the value of errno by calling perror(), so testing it afterwards isn't valid.
Just Change this in SERVER and it will work
fcntl(cfd, F_SETFL, O_NONBLOCK);
int size = read(cfd, buf, 1024);
if(size == -1)
printf("read error\n");
sleep(2); // sleep for a while to make sure the client closed the socket
int ret;
ret = write(cfd, buf, strlen(buf));
sleep(2);
ret = write(cfd, buf, strlen(buf)); // write again.
printf("write return %d\n", ret);

unix domain socket programming

I have a unix domain socket program, the client try to connect to the server and send a message, when the server accept the client and read the message,it will sleep for 5 seconds and send another message.During the 5 seconds if I use ctrl+c to kill the client,then the server will quit.How can I handle this situation?My program as follows:
client:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <string.h>
#include <assert.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#define INFO_SERVER_PATH "/var/info_server_path"
int create_route_client()
{
int client_fd;
int addr_len;
struct sockaddr_un server_addr;
if ((client_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
perror("create route info client socket");
return -1;
}
memset(&server_addr, 0, sizeof(struct sockaddr_un));
server_addr.sun_family = AF_LOCAL;
strcpy(server_addr.sun_path, INFO_SERVER_PATH);
addr_len = offsetof(struct sockaddr_un,sun_path) + strlen(server_addr.sun_path);
if (connect(client_fd, (struct sockaddr*)&server_addr, addr_len) < 0) {
perror("socket connect");
return -1;
}
return client_fd;
}
int main(int argc, char const *argv[])
{
char *sendline = "hello server";
char recvline[512];
int client_fd;
int nwrite;
int nread;
client_fd = create_route_client();
assert(client_fd > 0);
nwrite = write(client_fd, sendline, strlen(sendline));
if (nwrite < 0) {
perror("failed to send command to the info server");
close(client_fd);
return 1;
}
nread = read(client_fd, recvline, sizeof(recvline));
if (nread < 0) {
perror("failed to read route state");
close(client_fd);
return 1;
}
recvline[nread] = '\0';
printf("%s\n", recvline);
close(client_fd);
return 0;
}
server:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <string.h>
#include <assert.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#define INFO_SERVER_PATH "/var/info_server_path"
int create_command_server()
{
struct sockaddr_un server_addr;
size_t addr_len;
int server_fd;
if ((server_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("create socket");
return -1;
}
unlink(INFO_SERVER_PATH);
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, INFO_SERVER_PATH);
addr_len = offsetof(struct sockaddr_un, sun_path) + strlen(INFO_SERVER_PATH);
if (bind(server_fd, (struct sockaddr*)&server_addr, addr_len) < 0) {
perror("socket bind");
return -1;
}
if (listen(server_fd, 1) < 0) {
perror("socket listen");
return -1;
}
return server_fd;
}
int main(int argc, char const *argv[])
{
int info_server_fd = create_command_server();
char recvline[512];
char *sendline = "hello client";
int nread;
int nwrite;
while (1) {
int info_client_fd = accept(info_server_fd, NULL, NULL);
nread = read(info_client_fd, recvline, 512);
if (nread) {
int i;
for (i = 0; i < 5; i++) {
printf("i = %d\n", i);
sleep(1);
}
nwrite = write(info_client_fd , sendline, strlen(sendline));
printf("nwrite = %d\n", nwrite);
if (nwrite < 0)
perror("failed to send to client");
}
close(info_client_fd);
}
return 0;
}
Hard to tell exactly without compiling and running your code, but I'd guess you're getting a SIGPIPE signal due to writing to the connection that was closed when you killed the client. The default action for a process receiving SIGPIPE is to terminate the process.
You can block the SIGPIPE signal using sigprocmask(), or tell the kernel you want to block it, ignore it or register an asynchronous signal handler for it using sigaction(). Then, when you call write(), it will return -1 and errno will be set to EPIPE. See the man page for write() http://man7.org/linux/man-pages/man2/write.2.html.
See the man page for signals http://man7.org/linux/man-pages/man7/signal.7.html for more information on signals and how to handle them. But, be warned that handling signals should not be done using an asynchronous signal handler unless you are very very careful and know exactly what you are doing. This is the source of many bugs. It's safest (by far) to ignore them if you don't need them, or block them and use a synchronous signal handling approach, like sigwait() or a signal fd (Linux-specific). In your case, you don't need them. The write() call will tell you when the connection is gone.

Processes not terminating

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.

gcc: wrong behaviour after new variable was added

I am writing simple programs: server and client. You know, I am just learning all these stuff.
I added new variable (fileUp in server.c) and the client just crashed. I debugged it with gdb. The client can't read anything from the socket. Without that one variable works fine.
I did compile these programs with both gcc and g++ with -Wall. No errors, no warnings.
Programs are as simple as they can be. I don't understand what is wrong.
Any hint'll be appreciated.
server.c
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv) {
struct sockaddr_in address, client;
int s = socket(AF_INET, SOCK_STREAM, 0);
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
#define PORT 54321
address.sin_port = htons(PORT);
if(bind(s, (struct sockaddr *)&address, sizeof(address))<0) {
perror("nie udał się bind");
exit(-1);
}
if(listen(s, 5)<0) {
perror("nie udał się listen");
exit(-1);
}
socklen_t client_len;
int c = accept(s, (struct sockaddr *)&client, &client_len);
int file = open("../data", O_RDONLY);
if(file<0) {
perror("nie udało się otworzyć pliku");
exit(-1);
}
#define MAX 1024
char buf[MAX];
int n = read(file, buf, MAX);
int fileUp = n;
do {
write(c, buf, MAX);
buf[n-1] = '\0';
printf("%d: %s\n", n, buf);
/*fileUp += n;
printf("pobrano: %d\n", fileUp);*/
n = read(file, buf, MAX);
getchar();
} while(n != 0);
close(c);
close(s);
return 0;
}
client.c
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv) {
struct sockaddr_in address;
int s = socket(PF_INET, SOCK_STREAM, 0);
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
#define PORT 54321
address.sin_port = htons(PORT);
if(inet_pton(AF_INET, argv[1], &address.sin_addr) <=0) {
perror("podano nieprawidłowy adres");
exit(-1);
}
if(connect(s, (struct sockaddr *)&address, sizeof(address))<0) {
perror("nie można się połączyć");
exit(-1);
}
#define MAX 1024
char buf[MAX];
int n = read(s, buf, MAX);
int fileDown = n;
do {
buf[n-1] = '\0';
printf("%d: %s\n", n, buf);
n = read(s, buf, MAX);
fileDown += n;
printf("pobrano: %d\n", fileDown);
} while(n != 0);
close(s);
return 0;
}
socklen_t client_len; should be socklen_t client_len = sizeof(client);
The stack layout will change when you add your new variable - so the uninitialized value in client_len just happened to work before, it doesn't after - most likely making your accept call fail, and then you're trying to write to an invalid FD.
You should of course also check the return value of accept

Resources