sendfile on macOS and gcc - c

I am try to make most basic FTP feature in c language on macOS host mashine.
I use g++ or gcc compiler. I found c example for linux but sendfile is not the same prototype
like macos system support. I fix include with :
#if __APPLE__
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#elif
#include <sys/sendfile.h>
#endif
Interface:
OSX:
int sendfile(int fd, int s, off_t offset, off_t *len, struct sf_hdtr *hdtr, int flags);
Linux:
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
Whole file :
////FTP SERVER WITH TCP
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#if __APPLE__
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#elif
#include <sys/sendfile.h>
#endif
#include <fcntl.h>
/*
OSX:
int sendfile(int fd, int s, off_t offset, off_t *len, struct sf_hdtr *hdtr, int flags);
Linux:
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
*/
int main()
{
int sock_desc, sock_desc2;
socklen_t len;
struct stat obj;
char length[10];
int filehandle;
char choice[100];
int k, i;
char buf[100];
char target[100];
struct sockaddr_in client, server;
memset(&client, 0, sizeof(client));
memset(&server, 0, sizeof(server));
sock_desc = socket(AF_INET, SOCK_STREAM, 0);
if (sock_desc == -1)
{
puts("Error in socket 1");
exit(1);
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = 8045;
k = bind(sock_desc, (struct sockaddr *)&server, sizeof(server));
if (k == -1)
{
puts("Error in binding");
exit(1);
}
k = listen(sock_desc, 5);
if (k == -1)
{
puts("Error in listening");
exit(1);
}
len = sizeof(client);
sock_desc2 = accept(sock_desc, (struct sockaddr *)&client, &len);
if (sock_desc2 == -1)
{
puts("Error in socket2");
exit(1);
}
while (1)
{
k = recv(sock_desc2, buf, 100, 0);
if (k == -1)
{
puts("Error in receive");
exit(1);
}
for (i = 0; i < 4; i++)
{
choice[i] = buf[i];
}
choice[i] = '\0';
puts("");
puts(choice);
puts("");
if (strcmp(choice, "LIST") == 0)
{
system("ls -al>list.txt");
filehandle = open("list.txt", O_RDONLY); //
stat("list.txt", &obj); //
sprintf(length, "%d", (int)obj.st_size);
puts("sending size of file");
k = send(sock_desc2, length, strlen(length), 0);
if (k == -1)
{
printf("send failed");
exit(1);
}
puts("send entire file");
k = sendfile(sock_desc2, filehandle, NULL, obj.st_size);
if (k == -1)
{
printf("file sendingfailed");
exit(1);
}
}
else if (strcmp(choice, "LOAD") == 0)
{
puts("inside load");
strcpy(target, buf + 5);
printf("target file is*%s*\n", target);
memset(&obj, 0, sizeof(obj));
stat(target, &obj);
filehandle = open(target, O_RDONLY);
if (filehandle == -1)
{
puts("Error in opening file for read");
exit(1);
}
sprintf(length, "%d", (int)obj.st_size);
k = send(sock_desc2, length, strlen(length), 0);
if (k == -1)
{
puts("Error in sending");
exit(1);
}
k = sendfile(sock_desc2, filehandle, NULL, obj.st_size);
if (k == -1)
{
puts("Error in sending file");
exit(1);
}
}
}
}
UPDATE:
Ok, i wanted to make adaptation, to prepare args for sendfile also for macos. I count on thought 'it is a same compiler and linux and mac are based on UNIX' but it is not enough.
Look's like sockets feature also need totally different source and libs.
Question is simple transfer file in c on macos using gcc compiler.
I found interest imports:
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
Works on macos

Related

What can cause returning SO_EE_CODE_ZEROCOPY_COPIED when sending udp messages with MSG_ZEROCOPY?

Enviroment
Linux version: Linux 5.4.0-4-amd64 Debian 5.4.19-1 x86_64 GNU/Linux
NIC scatter-gather:
scatter-gather: on
tx-scatter-gather: on
tx-scatter-gather-fraglist: off [fixed]
Output
The sock_extended_err code is set to SO_EE_CODE_ZEROCOPY_COPIED. According to Linux Kernel Doc, when devices do not support scatter-gather I/O, this code will be returned, but you can see my NIC supports and enables scatter-gather I/O.
The doc linked is to show the official explanation for SO_EE_CODE_ZEROCOPY_COPIED, and linux supports udp msg_zerocopy for version >= 5.0
So, any ideas about other reasons? Or my code is wrong?
Code
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <error.h>
#include <errno.h>
#include <limits.h>
#include <linux/errqueue.h>
#include <linux/if_packet.h>
#include <linux/ipv6.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <poll.h>
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/rds.h>
#ifndef SO_EE_ORIGIN_ZEROCOPY
#define SO_EE_ORIGIN_ZEROCOPY 5
#endif
#ifndef SO_ZEROCOPY
#define SO_ZEROCOPY 60
#endif
#ifndef SO_EE_CODE_ZEROCOPY_COPIED
#define SO_EE_CODE_ZEROCOPY_COPIED 1
#endif
#ifndef MSG_ZEROCOPY
#define MSG_ZEROCOPY 0x4000000
#endif
#define TESTSIZE 16*1024
static char payload[TESTSIZE];
static long packets, bytes, completions, expected_completions;
static int zerocopied = -1;
static uint32_t next_completion;
static void do_setsockopt(int fd, int level, int optname, int val)
{
if (optname == SO_ZEROCOPY) {
printf("set so_zerocopy\n");
}
if (setsockopt(fd, level, optname, &val, sizeof(val)))
error(1, errno, "setsockopt %d.%d: %d", level, optname, val);
}
static bool do_sendmsg(int fd, struct msghdr *msg, bool do_zerocopy)
{
int ret, len, flags;
size_t i;
len = 0;
for (i = 0; i < msg->msg_iovlen; i++)
len += msg->msg_iov[i].iov_len;
flags = MSG_DONTWAIT;
if (do_zerocopy) {
printf("set msg_zerocopy\n");
flags |= MSG_ZEROCOPY;
}
ret = sendmsg(fd, msg, flags);
if (ret == -1 && errno == EAGAIN)
return false;
if (ret == -1)
error(1, errno, "send");
if (len) {
packets++;
bytes += ret;
if (do_zerocopy && ret)
expected_completions++;
}
return true;
}
static int do_setup_tx(int domain, int type, int protocol)
{
int fd;
fd = socket(domain, type, protocol);
if (fd == -1)
error(1, errno, "socket t");
do_setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, 1);
return fd;
}
static bool do_recv_completion(int fd)
{
struct sock_extended_err *serr;
struct msghdr msg = {};
struct cmsghdr *cm;
uint32_t hi, lo, range;
int ret, zerocopy;
char control[100];
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
if (ret == -1 && errno == EAGAIN)
return false;
if (ret == -1)
error(1, errno, "recvmsg notification");
if (msg.msg_flags & MSG_CTRUNC)
error(1, errno, "recvmsg notification: truncated");
cm = CMSG_FIRSTHDR(&msg);
if (!cm)
error(1, 0, "cmsg: no cmsg");
if (!((cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_RECVERR) ||
(cm->cmsg_level == SOL_IPV6 && cm->cmsg_type == IPV6_RECVERR) ||
(cm->cmsg_level == SOL_PACKET && cm->cmsg_type == PACKET_TX_TIMESTAMP)))
error(1, 0, "serr: wrong type: %d.%d",
cm->cmsg_level, cm->cmsg_type);
serr = (void *) CMSG_DATA(cm);
if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY)
error(1, 0, "serr: wrong origin: %u", serr->ee_origin);
if (serr->ee_errno != 0)
error(1, 0, "serr: wrong error code: %u", serr->ee_errno);
hi = serr->ee_data;
lo = serr->ee_info;
range = hi - lo + 1;
/* Detect notification gaps. These should not happen often, if at all.
* Gaps can occur due to drops, reordering and retransmissions.
*/
if (lo != next_completion)
fprintf(stderr, "gap: %u..%u does not append to %u\n",
lo, hi, next_completion);
next_completion = hi + 1;
zerocopy = !(serr->ee_code & SO_EE_CODE_ZEROCOPY_COPIED);
if (serr->ee_code == SO_EE_CODE_ZEROCOPY_COPIED) {
printf("zerocopy is not valid, but why? It is rediculous!\n");
}
else {
printf("zerocopy is available\n");
}
if (zerocopied == -1)
zerocopied = zerocopy;
else if (zerocopied != zerocopy) {
fprintf(stderr, "serr: inconsistent\n");
zerocopied = zerocopy;
}
completions += range;
return true;
}
static void do_tx(int domain, int type, int protocol)
{
struct iovec iov[3] = { {0} };
struct msghdr msg = {0};
int fd;
fd = do_setup_tx(domain, type, protocol);
struct sockaddr_in serv_addr;
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
inet_pton(AF_INET, "114.114.114.114", &serv_addr.sin_addr);
connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
iov[0].iov_base = payload;
iov[0].iov_len = sizeof(payload);
msg.msg_iovlen++;
msg.msg_iov = &iov[0];
// printf("sendmsg\n");
do_sendmsg(fd, &msg, true);
// printf("wait notification\n");
while(!do_recv_completion(fd));
sleep(1);
if (close(fd))
error(1, errno, "close");
fprintf(stderr, "tx=%lu (%lu B) txc=%lu zc=%c\n",
packets, bytes, completions,
zerocopied == 1 ? 'y' : 'n');
}
static void do_test(int domain, int type, int protocol)
{
int i;
for (i = 0; i < TESTSIZE; i++)
payload[i] = 'a' + (i % 26);
do_tx(domain, type, protocol);
}
int main()
{
do_test(AF_INET, SOCK_DGRAM, 0);
return 0;
}
After tracing kernel stack, i found that skb_copy_ubufs lead to the result, which was called by dev_queue_xmit_nit. It means that MSG_ZEROCOPY notification will return SO_EE_CODE_ZEROCOPY_COPIED if there are network taps in use. For my case, they are dhclient and lldpd.service. After killing them, the code disappeared.

C socket: recv jams the program if used twice

I'm trying to implement C code on a UNIX platform which sends all files data to the client, and uploading a file from the client to the server.
The first part is working but for the second part I've encountered an issue.
After some debugging I've found out that the server side jams the client when I'm using recv the second time in the code [I've marked it for your convenience].
I've tried to look up on guides or what I'm doing wrong but I couldn't find the issue for what causing the program to get stuck.
For de-bugging purposes I'm now trying to send an int from client to the server
server side
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <dirent.h>
#include <fcntl.h>
#define PORT 0x0da2
#define IP_ADDR 0x7f000001
#define QUEUE_LEN 20
int main(void)
{
//char directory[1024];
//chdir("server");
//getcwd(directory, sizeof(directory));
//printf("%s",directory);
DIR* directory;
struct dirent* ent;
int fd;
char buffer[1000] = {0};
char convert[100] = {0};
size_t array_size = 0;
struct stat fileStat;
if ((directory = opendir ("server")) == NULL)
{
perror ("Cannot open .");
return 1;
}
while ((ent = readdir(directory)) != NULL)
{
if (!( !strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) )
{
fd = openat(dirfd(directory), ent->d_name, 0);
if (fd == -1)
{
perror ("Can't get stats.");
return 1;
}
if(fstat(fd, &fileStat)== -1)
{
perror ("Can't get stats.");
return 1;
}
strcat(buffer,ent->d_name);
sprintf(convert,"%lld", (long long) fileStat.st_size);
strcat(buffer, " ");
strcat(buffer,convert);
strcat(buffer,"\n");
}
}
int listenS = socket(AF_INET, SOCK_STREAM, 0);
if (listenS < 0)
{
perror("socket");
return 1;
}
struct sockaddr_in s = {0};
s.sin_family = AF_INET;
s.sin_port = htons(PORT);
s.sin_addr.s_addr = htonl(IP_ADDR);
if (bind(listenS, (struct sockaddr*)&s, sizeof(s)) < 0)
{
perror("bind");
return 1;
}
if (listen(listenS, QUEUE_LEN) < 0)
{
perror("listen");
return 1;
}
struct sockaddr_in clientIn;
int clientInSize = sizeof clientIn;
while (1)
{
int newfd = accept(listenS, (struct sockaddr*)&clientIn, (socklen_t*)&clientInSize);
if (newfd < 0)
{
perror("accept");
return 1;
}
if (send(newfd, &buffer, strlen(buffer), 0) < 0)
{
perror("send");
return 1;
}
char namebuff[100] = {0};
char sizebuff[256] = {0};
//int size;
ssize_t nrecv;
int error = 0;
int fsize;
//int dataleft;
if ((nrecv = recv(newfd, &namebuff, sizeof(namebuff), 0)) < 0)
{
perror("recv");
return 1;
}
if((strstr(buffer,namebuff) != NULL))
{
error = -1;
if (send(newfd, &error, sizeof(int), 0) < 0)
{
perror("send");
return 1;
}
}
/*if ((nrecv = recv(newfd, &fsize, sizeof(int), 0)) < 0) //this line is what jams the program
{
perror("recv");
return 1;
}*/
if(error != -1) //
{
if ((nrecv = recv(newfd, &sizebuff, sizeof(sizebuff), 0)) < 0)
{
perror("recv");
return 1;
}
fsize = atoi(sizebuff);
}
printf("%s\n",namebuff);
printf("%d\n",fsize);
close(newfd);
}
close(listenS);
return 0;
}
client side
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <fcntl.h>
#define PORT 0x0da2
#define IP_ADDR 0x7f000001
int ctoi(char c) {
return c-'0';
}
int main(void)
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
ssize_t nrecv;
struct sockaddr_in s = {0};
s.sin_family = AF_INET;
s.sin_port = htons(PORT);
s.sin_addr.s_addr = htonl(IP_ADDR);
if (connect(sock, (struct sockaddr*)&s, sizeof(s)) < 0)
{
perror("connect");
return 1;
}
printf("Successfully connected.\n");
char buffer[1000] = {0};
if ((nrecv = recv(sock, &buffer, sizeof(buffer), 0)) < 0)
{
perror("recv");
return 1;
}
printf("./client list-files\n%s\n", buffer); //nrcev gives the size of the data is recived
int fd;
//int i;
//ssize_t nwrite, nread;
char sizebuff[256];
struct stat file_stat;
int numcheck = 0;
//char buffer2[4096];
char namebuff[100] = "coolfile.txt";
fd=open("coolfile.txt",O_RDONLY);
if (send(sock, &namebuff, strlen(namebuff), 0) < 0)
{
perror("send");
return 1;
}
/*if ((nrecv = recv(sock, &numcheck, sizeof(int), 0)) < 0)
{
perror("recv");
return 1;
}*/
if (numcheck == -1)
{
printf("file already exists in the server\n");
return 1;
}
if (fstat(fd, &file_stat) < 0)
{
printf("error");
return 1;
}
sprintf(sizebuff, "%ld", file_stat.st_size);
//printf("%s\n",sizebuff);
/*int number = 5;
if(send(sock, &number, sizeof(int), 0) < 0)
{
printf("error");
return 1;
}*/
if(send(sock, &sizebuff, strlen(sizebuff), 0) < 0);
{
printf("error");
return 1;
}
/*
nread = read(fd, buffer2, 4096);
for (i = 0; i < nread; i += nwrite)
{
nwrite = write(sock, buffer2 + i, nread - i);
}
} while (nread != 0);*/
return 0;
}
Thanks for your help!

Why am I receiving more bytes than I am sending C?

I am receiving more bytes than I am sending on server side, and the file I receive has some garbage characters at the start of my file.
client code
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <dirent.h>
#include <time.h>
int main() {
int serverPort, clientPort, clientSock, serverSock;
scanf("%d", &clientPort);
struct sockaddr_in cadd, sadd1, sadd2, clen, slen;
cadd.sin_family = AF_INET;
cadd.sin_addr.s_addr = inet_addr("127.0.0.1");
cadd.sin_port = htons(clientPort);
clientSock = socket(AF_INET, SOCK_STREAM, 0);
if(clientSock == -1)
fprintf(stderr, "unable to create socket: %s\n", strerror(errno));
int result = connect(clientSock, (struct sockaddr *)&cadd, sizeof(cadd) );
if(result == -1) {
fprintf(stderr, "unable to create socket: %s\n", strerror(errno));
return -1;
}
while(1) {
struct stat stat_buf;
off_t offset = 0;;
int choice = 1;
int fd = open("myList.txt", O_RDONLY);
if (fd == -1) {
fprintf(stderr, "unable to open %s", strerror(errno));
exit(1);
}
fstat(fd, &stat_buf);
offset = 0;
int size = (int)stat_buf.st_size;
printf("File size: %d\n", size);
send(clientSock, &size, sizeof(stat_buf.st_size), 0);
int sent = sendfile(clientSock, fd, &offset, stat_buf.st_size);
if(sent == -1) {
fprintf(stderr, "error sendfile: %s\n", strerror(errno));
exit(1);
}
if(sent != stat_buf.st_size) {
fprintf(stderr, "error sendfile %d of %d bytes\n", sent, (int)stat_buf.st_size);
exit(1);
}
printf("sendfile succesfull %d\n", sent);
break;
}
}
server code
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <dirent.h>
#include <time.h>
int main() {
int serverPort, sock;
printf("Enter port number: ");
scanf("%d", &serverPort);
struct sockaddr_in server1, server2;
int addrlen = sizeof(server2);
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == -1) {
fprintf(stderr, "unable to create socket: %s\n", strerror(errno));
exit(1);
}
server1.sin_family = AF_INET;
server1.sin_port = htons(serverPort);
int rc = bind(sock, (struct sockaddr *) &server1, sizeof(server1));
if(rc == -1) {
fprintf(stderr, "bind error: %s\n", strerror(errno));
close(rc);
exit(1);
}
rc = listen(sock, 1);
if(rc == -1) {
fprintf(stderr, "listen failed: %s\n", strerror(errno));
exit(1);
}
while(1) {
int con = accept(sock, (struct sockaddr *) &server2, &addrlen);
int crt = creat("please.txt", S_IRWXU), size, count = 0;
recv(con, &size, sizeof(size), 0);
while(1) {
char mssg[100];
memset(mssg, '\0', sizeof(mssg));
int n = recv(con, mssg, sizeof(mssg), 0);
int wrt = write(crt, mssg, n);
count = count + wrt;
printf("Count: %d\n", count);
if(count >= size)
break;
}
printf("Write successful\n");
}
}
Attaching the screen-shots
client send =>
[server recv] =>
In the client you do this:
send(clientSock, &size, sizeof(stat_buf.st_size), 0);
But in the server you do:
recv(con, &size, sizeof(size), 0);
size is an int, which is 4 bytes. But st_size is off_t, which is presumably 8 bytes. So you're only reading the first 4 bytes of the the size, and leaving the rest to be copied into the file. That's why you end up with 4 extra bytes on the server.
Declare size with the same data type as st_size, rather than int, and your problem should be solved.

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.

Connect Error in Basic TCP Client Server Programming in C

The server has to echo the message sent by the client using C program in Linux.I'm using Ubuntu OS (I don't know whether this information is useful or not!). It worked for the first time. But for the second time, it gave 'Error Connection'. I tried changing port numbers. But still it didn't work. Kindly guide me. I'm a beginner.
server.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
int main()
{
int sd, sd1, len, confd, n;
struct sockaddr_in ser, cli;
char msg[50];
if((sd = socket(AF_INET,SOCK_STREAM, 0)) < 0)
printf("\nSocket creation error\n");
bzero(&ser, sizeof(ser));
ser.sin_family = cli.sin_family = PF_INET;
ser.sin_port = htons(10000);
ser.sin_addr.s_addr = htonl(INADDR_ANY);
len = sizeof(ser);
if ((bind(sd, (struct sockaddr*)&ser, len)) < 0) {
printf("\nBind Error");
exit(0);
}
if (listen(sd, 2) == 0) {
if ((sd1 = accept(sd, (struct sockaddr*)&ser, &len)) > 0) {
do {
bzero(&msg, 50);
read(sd1, msg, 50);
//int m=(int)msg;
printf("\nMessage from client:%s\n", msg);
write(sd1, msg, strlen(msg));
if(strcmp(msg, "exit") == 0)
break;
} while(strcmp(msg, "exit") != 0);
}
}
}
*strong text*client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
int main()
{
int sd, n, len;
struct sockaddr_in ser, cli;
char text[50];
if ((sd = socket(AF_INET,SOCK_STREAM, 0)) < 0)
printf("\nSocket creation error\n");
bzero(&ser, sizeof(ser));
ser.sin_family = cli.sin_family = PF_INET;
ser.sin_port = htons(10000);
ser.sin_addr.s_addr = htonl(INADDR_ANY);
len = sizeof(ser);
if ((connect(sd, (struct sockaddr*)&ser, len)) < 0) {
printf("\nError connection");
exit(0);
}
while(1) {
strcpy(text, " ");
printf("\nEnter data which is to be sent:");
scanf("%s", text);
write(sd, text, strlen(text));
read(sd, text, 50);
printf("\nEcho msg from server:%s", text);
if (strcmp(text, "exit") == 0)
break;
}
close(sd);
}
Can your client really connect to any address?
ser.sin_addr.s_addr=htonl(INADDR_ANY);
Most likely you meant to connect to a specific server:
ser.sin_addr.s_addr=inet_addr("127.0.0.1");

Resources