Related
My server and client are communicating back and forth using two named pipes (fifo) in C until the server receives an exit message.
Apparently the server side blocks the second time it tries to read() from its FIFO despite the client writing to it successfully. I think the problem is that the server tries to read() sooner than the client could write() to it.
Here is the server:
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "header.h"
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>
int main(int argc, char *argv[]) {
//fifo for the server to read from
if (mkfifo(FIFONAME, S_IFIFO|0666) < 0) {
if (errno != EEXIST) {
perror("Error with mkfifo");
exit(1);
}
}
int f;
if ((f = open(FIFONAME, O_RDONLY)) < 0) {
perror("Error with open");
exit(1);
}
Message msg;
while(1) {
if ((read(f, &msg, sizeof(Message))) > 0) {
if (strcmp(msg.user, "exit") == 0) {
close(f);
unlink(FIFONAME);
exit(0);
}
if (strcmp(msg.user, "new client") == 0) {
switch (fork()) {
case -1:{
perror("Error with fork");
exit(1);
}
case 0:{
char gender[MAXLEN];
char client_fifo[30];
sprintf(msg.user, "I need client's gender\n");
sprintf(client_fifo, "fifo_%d", msg.pid);
msg.pid = getpid();
int o;
//open client's fifo for server to write to
if ((o = open(client_fifo, O_WRONLY)) == -1) {
perror("Error opening client fifo");
exit(1);
}
//send message
write(o, &msg, sizeof(Message));
//read client's answer, but program blocks here
if ((read(f, &msg, sizeof(Message))) > 0) {
sprintf(gender,"%s", msg.user);
printf("Client's gender is %s\n", gender);
}
close(o);
exit(0);
}
}
}
}
}
return 0;
}
The client code:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include "header.h"
#include <unistd.h>
int f,fc;
char fifoname[20];
Message msg;
int main(int argc, char* argv[]) {
sprintf(fifoname, "fifo_%d", getpid());
if (mkfifo(fifoname, S_IFIFO | 0666) < 0) {
perror("Error with client's fifo");
printf("Could not create fifo_%d", getpid());
exit(1);
}
if ((f=open(FIFONAME,O_WRONLY))<0) {
perror("Error connecting to server");
exit(2);
}
char gender[MAXLEN];
strcpy(msg.user, "new client");
msg.pid = getpid();
//first message to server
write(f, &msg, sizeof(msg));
char arg[MAXLEN];
if (argc > 1) {
strcpy(arg, argv[1]);
} else {
strcpy(arg, "work");
}
if (strcmp(arg, "exit")) {
if ((fc = open(fifoname, O_RDONLY))<0) {
perror("Error opening client's fifo");
printf("Could not open my fifo");
exit(3);
}
if (read(fc, &msg, sizeof(msg)) > 0) {
printf("%s\n",msg.user);
}
scanf("%s", gender);
strcpy(msg.user, gender);
msg.pid = getpid();
printf("writing gender...\n");
write(f, &msg, sizeof(msg));
//program successfully reaches this print:
printf("gender written\n");
close(fc);
}
unlink(fifoname);
close(f);
exit(0);
}
And the header containing the struct for the message:
#define MAXLEN 20
typedef struct {
int pid;
char user[MAXLEN];
} Message;
#define FIFONAME "fifo_server"
I need to write further back and forth messages like this but I don't know how to get the server not to block on the second call of read()
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
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.
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h> //Unable to find all of this header files
#include <signal.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <netdb.h>
I want to use this header files ion my program and i cannot find it on the internet please provide a source from which i could get them
On windows, socket api is packed into a different set of headers. But the way the windows sockets work (if used in a "portable" way) is pretty much the same as on unix systems. Give or take.
The example code from the other question you linked looks like this on windows:
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
//#include <netinet/in.h>
#include <WinSock2.h>
#include <Ws2tcpip.h>
//#include <sys/wait.h>
//#include <sys/socket.h>
//#include <signal.h>
#include <ctype.h>
//#include <arpa/inet.h>
//#include <netdb.h>
#define PORT 20000
#define LENGTH 512
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
/* Variable Definition */
SOCKET sockfd;
char revbuf[LENGTH];
struct sockaddr_in remote_addr;
/* Get the Socket file descriptor */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor! (errno = %d)\n", errno);
exit(1);
}
/* Fill the socket address struct */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr);
ZeroMemory(&(remote_addr.sin_zero), 8);
/* Try to connect the remote */
if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "ERROR: Failed to connect to the host! (errno = %d)\n", errno);
exit(1);
}
else
printf("[Client] Connected to server at port %d...ok!\n", PORT);
/* Send File to Server */
//if(!fork())
//{
char* fs_name = "/home/aryan/Desktop/quotidiani.txt";
char sdbuf[LENGTH];
printf("[Client] Sending %s to the Server... ", fs_name);
FILE *fs = NULL;
errno_t err = fopen_s(&fs, fs_name, "r");
if (fs == NULL)
{
printf("ERROR: File %s not found.\n", fs_name);
exit(1);
}
ZeroMemory(sdbuf, LENGTH);
int fs_block_sz;
while ((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
{
if (send(sockfd, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
break;
}
ZeroMemory(sdbuf, LENGTH);
}
printf("Ok File %s from Client was Sent!\n", fs_name);
//}
/* Receive File from Server */
printf("[Client] Receiveing file from Server and saving it as final.txt...");
char* fr_name = "/home/aryan/Desktop/progetto/final.txt";
FILE *fr = NULL;
err = fopen_s(&fr, fr_name, "a");
if (fr == NULL)
printf("File %s Cannot be opened.\n", fr_name);
else
{
ZeroMemory(revbuf, LENGTH);
int fr_block_sz = 0;
while ((fr_block_sz = recv(sockfd, revbuf, LENGTH, 0)) > 0)
{
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if (write_sz < fr_block_sz)
{
error("File write failed.\n");
}
ZeroMemory(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512)
{
break;
}
}
if (fr_block_sz < 0)
{
if (errno == EAGAIN)
{
printf("recv() timed out.\n");
}
else
{
fprintf(stderr, "recv() failed due to errno = %d\n", errno);
}
}
printf("Ok received from server!\n");
fclose(fr);
}
//close(sockfd);
closesocket(sockfd);
printf("[Client] Connection lost.\n");
return (0);
}
Now you can compare and see what is the same and what is a bit different. Hope that helps you to understand.
In case, you wonder next, why you have linker errors: Link against ws2_32.lib. In contrast to unix systems, where sockets are part of "libc", sockets are factored out into a separate dll in windows.
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.