Related
I have a list of millions of IP addresses of web servers. I want to check they are up and running by doing a non blocking connect to each of the servers. I know from the reading I've done so far that it is theoretically possible to handle 10,000 concurrent connects to different servers using epoll. See the C10K problem for more information.
Can anyone provide a sample epoll based code that demonstrates how to connect to multiple servers on port 80 concurrently and remove finished jobs and add new ones to replace those that are finished?
Below I include code I have done so far. I have managed to do the asynchronous DNS part of the code that gets the IP addresses from a list of domain names.
#include <ares.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#define MAXWAITING 1000 /* Max. number of parallel DNS queries */
#define MAXTRIES 3 /* Max. number of tries per domain */
#define TIMEOUT 3000 /* Max. number of ms for first try */
#define SERVERS "1.0.0.1,8.8.8.8" /* DNS server to use (Cloudflare & Google) */
static int nwaiting;
static void
state_cb(void *data, int s, int read, int write)
{
//printf("Change state fd %d read:%d write:%d\n", s, read, write);
}
static void
callback(void *arg, int status, int timeouts, struct hostent *host)
{
nwaiting--;
if(!host || status != ARES_SUCCESS){
fprintf(stderr, "Failed to lookup %s\n", ares_strerror(status));
return;
}
char ip[INET6_ADDRSTRLEN];
if (host->h_addr_list[0] != NULL){
inet_ntop(host->h_addrtype, host->h_addr_list[0], ip, sizeof(ip));
printf("%s\n", ip);
}
}
static void
wait_ares(ares_channel channel)
{
struct timeval *tvp, tv;
fd_set read_fds, write_fds;
int nfds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
nfds = ares_fds(channel, &read_fds, &write_fds);
if (nfds > 0) {
tvp = ares_timeout(channel, NULL, &tv);
select(nfds, &read_fds, &write_fds, NULL, tvp);
ares_process(channel, &read_fds, &write_fds);
}
}
int
main(int argc, char *argv[])
{
FILE * fp;
char domain[128];
size_t len = 0;
ssize_t read;
ares_channel channel;
int status, done = 0;
int optmask;
status = ares_library_init(ARES_LIB_INIT_ALL);
if (status != ARES_SUCCESS) {
printf("ares_library_init: %s\n", ares_strerror(status));
return 1;
}
struct ares_options options = {
.timeout = TIMEOUT, /* set first query timeout */
.tries = MAXTRIES /* set max. number of tries */
};
optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES;
status = ares_init_options(&channel, &options, optmask);
if (status != ARES_SUCCESS) {
printf("ares_init_options: %s\n", ares_strerror(status));
return 1;
}
status = ares_set_servers_csv(channel, SERVERS);
if (status != ARES_SUCCESS) {
printf("ares_set_servers_csv: %s\n", ares_strerror(status));
return 1;
}
fp = fopen(argv[1], "r");
if (!fp)
exit(EXIT_FAILURE);
do {
if (nwaiting >= MAXWAITING || done) {
do {
wait_ares(channel);
} while (nwaiting > MAXWAITING);
}
if (!done) {
if (fscanf(fp, "%127s", domain) == 1) {
ares_gethostbyname(channel, domain, AF_INET, callback, NULL);
nwaiting++;
} else {
fprintf(stderr, "done sending\n");
done = 1;
}
}
} while (nwaiting > 0);
ares_destroy(channel);
ares_library_cleanup();
fclose(fp);
return 0;
}
I have also managed to make a start on the epoll code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 80
#define MAXBUF 1024
#define MAX_EPOLL_EVENTS 64
#define MAX_CONNECTIONS 1024
int main(int argc, char *argv[]) {
FILE * fp;
char servers[MAX_CONNECTIONS][128];
int sockfd[MAX_CONNECTIONS];
struct sockaddr_in dest[MAX_CONNECTIONS];
char buffer[MAX_CONNECTIONS][MAXBUF];
struct epoll_event events[MAX_EPOLL_EVENTS];
int i, num_ready, connections = 0;
fp = fopen(argv[1], "r");
if (!fp)
exit(EXIT_FAILURE);
/*---Open socket for streaming---*/
for (i = 0; i < MAX_CONNECTIONS; i++)
{
if ( (sockfd[i] = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0)) < 0 ) {
perror("Socket");
exit(errno);
}
}
/*---Add socket to epoll---*/
int epfd = epoll_create(1);
struct epoll_event event[MAX_CONNECTIONS];
for (i = 0; i < MAX_CONNECTIONS; i++)
{
event[i].events = EPOLLIN; // Cann append "|EPOLLOUT" for write events as well
event[i].data.fd = sockfd[i];
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd[i], &event[i]);
}
/*---Initialize server address/port struct---*/
for (i = 0; i < MAX_CONNECTIONS; i++)
{
if (fscanf(fp, "%127s", servers[i]) == 1)
{
//printf("Adding ip %s\n", servers[i]);
bzero(&dest[i], sizeof(dest[i]));
dest[i].sin_family = AF_INET;
dest[i].sin_port = htons(PORT);
if ( inet_pton(AF_INET, servers[i], &dest[i].sin_addr.s_addr) == 0 ) {
perror(servers[i]);
exit(errno);
}
}
else
{
break;
}
}
/*---Connect to server---*/
for (i = 0; i < MAX_CONNECTIONS; i++)
{
if ( connect(sockfd[i], (struct sockaddr*)&dest[i], sizeof(dest[i])) != 0 ) {
if(errno != EINPROGRESS) {
perror("Connect ");
exit(errno);
}
}
}
while (1)
{
/*---Wait for socket connect to complete---*/
num_ready = epoll_wait(epfd, events, MAX_EPOLL_EVENTS, 1000/*timeout*/);
for(i = 0; i < num_ready; i++) {
if(events[i].events & EPOLLIN) {
//printf("Socket %d connected\n", events[i].data.fd);
}
}
/*---Wait for data---*/
num_ready = epoll_wait(epfd, events, MAX_EPOLL_EVENTS, 1000/*timeout*/);
for(i = 0; i < num_ready; i++) {
if(events[i].events & EPOLLIN) {
//printf("Socket %d got some data\n", events[i].data.fd);
connections++;
printf("%d\r", connections);
bzero(buffer[events[i].data.fd], MAXBUF);
recv(sockfd[events[i].data.fd], buffer[events[i].data.fd], sizeof(buffer[i]), 0);
//printf("Received: %s\n", buffer[events[i].data.fd]);
close(sockfd[events[i].data.fd]);
epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd[events[i].data.fd], &event[events[i].data.fd]);
if (fscanf(fp, "%127s", servers[events[i].data.fd]) == 1)
{
if ( (sockfd[events[i].data.fd] = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0)) < 0 ) {
perror("Socket");
exit(errno);
}
event[events[i].data.fd].events = EPOLLIN; // Cann append "|EPOLLOUT" for write events as well
event[events[i].data.fd].data.fd = sockfd[events[i].data.fd];
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd[events[i].data.fd], &event[events[i].data.fd]);
//printf("Adding ip %s\n", servers[events[i].data.fd]);
bzero(&dest[events[i].data.fd], sizeof(dest[events[i].data.fd]));
dest[events[i].data.fd].sin_family = AF_INET;
dest[events[i].data.fd].sin_port = htons(PORT);
if ( inet_pton(AF_INET, servers[events[i].data.fd], &dest[events[i].data.fd].sin_addr.s_addr) == 0 ) {
printf("\n");
perror(servers[events[i].data.fd]);
exit(errno);
}
if ( connect(sockfd[events[i].data.fd], (struct sockaddr*)&dest[events[i].data.fd], sizeof(dest[events[i].data.fd])) != 0 ) {
if(errno != EINPROGRESS) {
perror("Connect again ");
exit(errno);
}
}
}
}
}
}
for (i = 0; i < MAX_CONNECTIONS; i++)
{
close(sockfd[i]);
}
printf("Finished without errors\n");
return 0;
}
The code compiles and runs but gives the following error:
5Connect again : Network is unreachable
This is what I came up with eventually:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 80
#define MAXBUF 1024
#define MAX_EPOLL_EVENTS 1024
#define MAX_CONNECTIONS 4096
#define TIMEOUT 10000
int sockfd[MAX_CONNECTIONS];
struct epoll_event event[MAX_CONNECTIONS];
int epfd;
struct sockaddr_in dest[MAX_CONNECTIONS];
char servers[MAX_CONNECTIONS][128];
void close_socket (int socket)
{
close(sockfd[socket]);
epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd[socket], &event[socket]);
}
void make_socket_and_connect (int sock)
{
if ( (sockfd[sock] = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0)) < 0 ) {
perror("Socket");
exit(errno);
}
event[sock].events = EPOLLIN; // Cann append "|EPOLLOUT" for write events as well
event[sock].data.fd = sockfd[sock];
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd[sock], &event[sock]);
bzero(&dest[sock], sizeof(dest[sock]));
dest[sock].sin_family = AF_INET;
dest[sock].sin_port = htons(PORT);
if ( inet_pton(AF_INET, servers[sock], &dest[sock].sin_addr.s_addr) == 0 ) {
printf("\n");
perror(servers[sock]);
exit(errno);
}
if ( connect(sockfd[sock], (struct sockaddr*)&dest[sock], sizeof(dest[sock])) != 0 ) {
if(errno != EINPROGRESS) {
printf("%s\n", servers[sock]);
perror("Connect again ");
//exit(errno);
}
}
}
int is_valid_ip(char *domain)
{
if (!strcmp(domain, "255.255.255.255"))
return 0;
if (!strcmp(domain, "192.168.1.0"))
return 0;
if (!strcmp(domain, "127.0.0.0"))
return 0;
return 1;
}
int main(int argc, char *argv[]) {
FILE * fp;
char buffer[MAX_CONNECTIONS][MAXBUF];
struct epoll_event events[MAX_EPOLL_EVENTS];
int i, num_ready, connections = 0, done = 0;
fp = fopen(argv[1], "r");
if (!fp)
exit(EXIT_FAILURE);
/*---Open socket for streaming---*/
for (i = 0; i < MAX_CONNECTIONS; i++)
{
if ( (sockfd[i] = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0)) < 0 ) {
perror("Socket");
exit(errno);
}
}
/*---Add socket to epoll---*/
epfd = epoll_create(1);
for (i = 0; i < MAX_CONNECTIONS; i++)
{
event[i].events = EPOLLIN; // Cann append "|EPOLLOUT" for write events as well
event[i].data.fd = sockfd[i];
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd[i], &event[i]);
}
/*---Initialize server address/port struct---*/
for (i = 0; i < MAX_CONNECTIONS; i++)
{
if (fscanf(fp, "%127s", servers[i]) == 1)
{
//printf("Adding ip %s\n", servers[i]);
bzero(&dest[i], sizeof(dest[i]));
dest[i].sin_family = AF_INET;
dest[i].sin_port = htons(PORT);
if ( inet_pton(AF_INET, servers[i], &dest[i].sin_addr.s_addr) == 0 ) {
perror(servers[i]);
exit(errno);
}
}
else
{
break;
}
}
/*---Connect to server---*/
for (i = 0; i < MAX_CONNECTIONS; i++)
{
if ( connect(sockfd[i], (struct sockaddr*)&dest[i], sizeof(dest[i])) != 0 ) {
if(errno != EINPROGRESS) {
perror("Connect ");
exit(errno);
}
}
}
while (1)
{
/*---Wait for socket connect to complete---*/
num_ready = epoll_wait(epfd, events, MAX_EPOLL_EVENTS, TIMEOUT/*timeout*/);
if (!num_ready) break;
for(i = 0; i < num_ready; i++) {
if(events[i].events & EPOLLIN) {
connections++;
printf("%d\r", connections);
close_socket(events[i].data.fd);
if (!done)
{
get_domain_name:
if (fscanf(fp, "%127s", servers[events[i].data.fd]) == 1)
{
if (is_valid_ip(servers[events[i].data.fd]))
make_socket_and_connect(events[i].data.fd);
else
goto get_domain_name;
}
else
{
done = 1;
}
}
}
}
}
for (i = 0; i < MAX_CONNECTIONS; i++)
{
close(sockfd[i]);
}
printf("Finished without errors\n");
return 0;
}
Try it. It's fast.
I have a client and server, the server is setup this way:
int listenS = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in s = { 0 };
s.sin_family = AF_INET;
s.sin_port = htons(PORT);
s.sin_addr.s_addr = htonl(IP_ADDR);
bind(listenS, (struct sockaddr*)&s, sizeof(s));
listen(listenS, QUEUE_LEN);
struct sockaddr_in clientIn;
int clientInSize = sizeof clientIn;
while (1)
{
int newfd = accept(listenS, (struct sockaddr*)&clientIn, (socklen_t*)&clientInSize);
//......
(There are tests I just removed them to make the code more readable)
The client is just:
int sock = socket(AF_INET, SOCK_STREAM, 0), 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)
{ //......
I get a connection, and everything is working great, the server recv a message the first time I send it from the client, but when I try to send another message to the server the server wont block the recv call and get nothing (returning the buffer size, not 0)
Here is the client code:
#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 <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#define PORT 0x0da2
#define IP_ADDR 0x7f000001
#define MAX_BUFFER_SIZE 1024
int send_all(int socket, void* buffer, size_t length)
{
char *ptr = (char*)buffer;
while (length > 0)
{
int i = send(socket, ptr, length, 0);
if (i < 1) return -1;
ptr += i;
length -= i;
}
return 0;
}
int main(int argc, char** argv)
{
if (argc > 1)
{
if ((strcmp(argv[1], "list-files") != 0) &&
(strcmp(argv[1], "upload-file") != 0) &&
(strcmp(argv[1], "download-file") != 0) &&
(strcmp(argv[1], "search") != 0))
{
perror("The arguments are incorrect.");
}
int sock = socket(AF_INET, SOCK_STREAM, 0), 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 sendBuffer[MAX_BUFFER_SIZE];
int lenOfArgv = strlen(argv[1]);
int sendBufferIndex = 0;
for (int i = 0;
i < lenOfArgv && sendBufferIndex < MAX_BUFFER_SIZE;
i++, sendBufferIndex++)
{
sendBuffer[sendBufferIndex] = argv[1][i];
}
if (argc == 3)
{
sendBuffer[sendBufferIndex++] = ' ';
int lenOfArgv = strlen(argv[2]);
for (int i = 0;
i < lenOfArgv && sendBufferIndex < MAX_BUFFER_SIZE;
i++, sendBufferIndex++)
{
sendBuffer[sendBufferIndex] = argv[2][i];
}
}
sendBuffer[sendBufferIndex] = 0;
// + 1 for terminating null
if (send_all(sock, sendBuffer, strlen(sendBuffer) + 1) < 0)
{
perror("send buffer to server failed");
return 1;
}
if(strcmp(argv[1], "download-file") == 0)
{
char sizeBuffer[256];
recv(sock, sizeBuffer, 256, 0);
int fileSize = atoi(sizeBuffer);
if(fileSize > 0)
{
FILE* recievedFile = fopen(argv[2], "w");
if(recievedFile != NULL)
{
int remainData = fileSize;
size_t len;
char fileBuffer[MAX_BUFFER_SIZE];
while(((len = recv(sock, fileBuffer, MAX_BUFFER_SIZE, 0)) > 0 && (remainData > 0)))
{
fwrite(fileBuffer, sizeof(char), len, recievedFile);
remainData -= len;
printf("Received %d bytes, %d is left..\n", len, remainData);
}
fclose(recievedFile);
printf("File downloaded!\n");
}
else
{
perror("Failed to download file\n");
}
}
}
else if(strcmp(argv[1], "upload-file") == 0)
{
char filePath[MAX_BUFFER_SIZE];
sprintf(filePath, "%s", argv[2]);
int fd = open(filePath, O_RDONLY);
int downloadFailed = 0;
if (fd != -1)
{
struct stat file_stat;
if(fstat(fd, &file_stat) >= 0)
{
char fileSize[256];
sprintf(fileSize, "%d", (int)file_stat.st_size);
int len = send(sock, fileSize, sizeof(fileSize), 0);
if(len >= 0)
{
int remainData = file_stat.st_size;
off_t offset = 0;
int sent_bytes = 0;
while(((sent_bytes = sendfile(sock, fd, &offset, MAX_BUFFER_SIZE)) > 0) && (remainData > 0))
{
remainData -= sent_bytes;
printf("sent %d bytes, %d is left...\n", sent_bytes, remainData);
}
}else {downloadFailed = 1;}
}else {downloadFailed = 1;}
}else {downloadFailed = 1;}
if(downloadFailed == 1)
{
perror("Failed to download file!\n");
}
}
else
{
char someBuffer[MAX_BUFFER_SIZE];
// nrecv is the number of bytes that we recieved
if ((nrecv = recv(sock, someBuffer, MAX_BUFFER_SIZE, 0)) < 0)
{
perror("recv");
return 1;
}
printf("%s\n", someBuffer);
}
close(sock);
return 0;
}
else
{
perror("The arguments are incorrect.");
}
}
here is the server code:
#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 <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <math.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#define PORT 0x0da2 // 3490
#define IP_ADDR 0x7f000001 // 127.0.0.1
#define QUEUE_LEN 20
#define MAX_BUFFER_SIZE 1024
int send_all(int socket, void* buffer, int length)
{
char *ptr = (char*)buffer;
while (length > 0)
{
int i = send(socket, ptr, length, 0);
if (i < 1) return -1;
ptr += i;
length -= i;
}
return 0;
}
void list_dir()
{
DIR * directory;
struct dirent* dir;
directory = opendir(".");
if (directory)
{
while ((dir = readdir(directory)) != NULL)
{
printf("%s\n", dir->d_name); // /home/text.txt, text.txt
// get filesize (in bytes0 with dir->d_name
}
}
}
void list_files(char* buffer, int withBytes = 0)
{
DIR* d;
struct dirent* dir;
d = opendir("data");
int bufferIndex = 0;
while((dir = readdir(d)) != NULL)
{
char tempFilename[256] = "data/";
int tempIndex = 5;
char* scan = dir->d_name;
while(*scan)
{
tempFilename[tempIndex++] = *scan;
buffer[bufferIndex++] = *scan++;
}
tempFilename[tempIndex] = 0;
struct stat st = {0};
stat(tempFilename, &st);
int fileSize = st.st_size;
if(withBytes == 1)
{
// Adding file size to the buffer
bufferIndex += sprintf(&buffer[bufferIndex], " %d bytes", fileSize);
}
buffer[bufferIndex++] = '\n';
}
buffer[bufferIndex] = 0;
closedir(d);
}
int main(void)
{
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;
struct stat st = {0};
if(stat("data", &st) == -1)
{
mkdir("data", 0700);
}
while (1)
{
int newfd = accept(listenS, (struct sockaddr*)&clientIn, (socklen_t*)&clientInSize);
if (newfd < 0)
{
perror("accept");
return 1;
}
int pid = fork(); // creating new thread
if (pid == 0)
{
close(listenS); // duplicate=> thats why we need to close the socket
char someBuffer[MAX_BUFFER_SIZE];
int nrecv;
if ((nrecv = recv(newfd, someBuffer, MAX_BUFFER_SIZE, 0)) < 0)
{
perror("recv");
return 1;
}
printf("Message recieved: %s\n", someBuffer);
// Here we read the command the argument and split them
// into seperate variables
char command[256];
char argument[256];
int commandHasBeenSet = 0;
char* token = strtok(someBuffer, " ");
while(token != NULL)
{
if(commandHasBeenSet == 0)
{
strcpy(command, token);
commandHasBeenSet = 1;
}
else
{
strcpy(argument, token);
}
token = strtok(NULL, " ");
}
if (strcmp(command, "list-files") == 0)
{
char buffer[MAX_BUFFER_SIZE];
list_files(buffer, 1);
if (send_all(newfd, buffer, strlen(buffer) + 1) < 0)
{
perror("send buffer to client failed");
return 1;
}
printf("Sent a message to a client!\n");
}
else if (strcmp(command, "upload-file") == 0)
{
printf("Uploading file %s\n", argument);
char sizeBuffer[256];
recv(newfd, sizeBuffer, 256, 0);
int fileSize = atoi(sizeBuffer);
if(fileSize > 0)
{
char filePath[MAX_BUFFER_SIZE];
sprintf(filePath, "data/%s", argument);
printf("Downloading to %s", filePath);
FILE* recievedFile = fopen(filePath, "w");
if(recievedFile != NULL)
{
int remainData = fileSize;
size_t len;
char fileBuffer[MAX_BUFFER_SIZE];
while(((len = recv(newfd, fileBuffer, MAX_BUFFER_SIZE, 0)) > 0 && (remainData > 0)))
{
fwrite(fileBuffer, sizeof(char), len, recievedFile);
remainData -= len;
printf("Received %d bytes, %d is left..\n", len, remainData);
}
fclose(recievedFile);
printf("File downloaded!\n");
}
else
{
perror("Failed to download file\n");
}
}else
{
perror("Failed to get file size for download\n");
}
}
else if (strcmp(command, "download-file") == 0)
{
char filePath[MAX_BUFFER_SIZE];
sprintf(filePath, "data/%s", argument);
int fd = open(filePath, O_RDONLY);
int downloadFailed = 0;
if (fd != -1)
{
struct stat file_stat;
if(fstat(fd, &file_stat) >= 0)
{
char fileSize[256];
sprintf(fileSize, "%d", (int)file_stat.st_size);
int len = send(newfd, fileSize, sizeof(fileSize), 0);
if(len >= 0)
{
int remainData = file_stat.st_size;
off_t offset = 0;
int sent_bytes = 0;
while(((sent_bytes = sendfile(newfd, fd, &offset, MAX_BUFFER_SIZE)) > 0) && (remainData > 0))
{
remainData -= sent_bytes;
printf("Server sent %d bytes, %d is left...\n", sent_bytes, remainData);
}
}else {downloadFailed = 1;}
}else {downloadFailed = 1;}
}else {downloadFailed = 1;}
if(downloadFailed == 1)
{
perror("Failed to download file!\n");
}
}
else if (strcmp(command, "search") == 0)
{
char buffer[MAX_BUFFER_SIZE];
char result[MAX_BUFFER_SIZE];
int resultIndex = 0;
list_files(buffer);
result[0] = 0;
char tempBuffer[MAX_BUFFER_SIZE];
strcpy(tempBuffer, buffer);
token = strtok(tempBuffer, "\n");
while(token != NULL)
{
char* scanToken = token;
char* scanArgument = argument;
int found = 1;
while(*scanToken && *scanArgument)
{
if(*scanToken++ != *scanArgument++)
{
found = 0;
break;
}
}
if(found == 1)
{
if(resultIndex > 0)
{
result[resultIndex++] = ' ';
}
strcpy(&result[resultIndex], token);
resultIndex += strlen(token);
result[resultIndex] = 0;
}
token = strtok(NULL, "\n");
}
if (send_all(newfd, result, strlen(result) + 1) < 0)
{
perror("send buffer to client failed");
return 1;
}
printf("Sent a message to a client!\n");
}
close(newfd);
exit(0);
}
else
close(newfd);
}
close(listenS);
return 0;
}
If you run the server, and then run the client with commands like:
./client list-files
./client download-file test.txt
it will work fine, the client will receive messages from the server and vice versa.
The problem occurs when I try to run:
./client upload-file test.txt
which is essentially the same as download-file command, just copied and pasted to the server from the client (same logic, should work the same), except it doesn't.
Specifically the program fail at line 175 of the server (recv(newfd, sizeBuffer, 256, 0);), it gets 0 instead of the value the client is sending it.
Any idea what I am missing?
(I tried searching online but didn't find anything)
TCP is a streaming protocol. There is no message boundaries, and server's recvs do not correspond to client's sends.
The client sends the command with
send_all(sock, sendBuffer, strlen(sendBuffer) + 1)
OTOH, the server tries to receive it with
nrecv = recv(newfd, someBuffer, MAX_BUFFER_SIZE, 0))
recv does not care whether the stream contains a '\0' or not. It blindly waits for MAX_BUFFER_SIZE bytes to come in. Some (valuable) data sent by the client is in someBuffer just past the command, but ignored by the server.
The server must parse the reply more diligently. For that you likely need a more elaborated protocol (e.g. prefix each string with its length).
You are assuming the stream socket will preserve your message boundaries. It will not. So, you're sending something like:
upload-file filename\0
NNN\0\0\0...\0 [256 bytes containing filesize]
<content of filename>
So probably the first recv you do on the server side (of MAX_BUFFER_SIZE bytes) is receiving not just the command string and the filename, but also the file size block and the entire file content. That is, you've already received it all and it's sitting in someBuffer. Your initial command string is null-terminated so you would not be aware of the rest of it unless you check nrecv. Hence, your next recv call gets end-of-file because the client is finished and has closed its end of the connection.
To send defined records over TCP, you need to know exactly how many bytes are expected at each point, and receive exactly those (or be prepared to parse the received data). See also https://stackoverflow.com/a/47440054/1076479
Its using a blocking queue for encrypting files with XOR.
The buffers are set to be very big, but still when i encrypt the encryption of big files (1000 chars and more) I should receive the same file, but I am receiving only the beginning. Anyone knows how to fix this?
thanks.
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/select.h>
#include <netinet/tcp.h>
#include "os_queue.c"
#define BACKLOGGED_CONNECTIONS 10
queue_t new_queue;
int i=0;
void *worker_thread(void* key_path) {
int j = i;
i++;
printf("worker %d stssssart\n",j);
int rc;
int sockfd;
int key_fd;
if ((key_fd = open(key_path, O_RDONLY)) < 0) {
printf("ERROR: open key file failed: %s\n",strerror(errno));
exit(1);
}
while (1) {
rc = queue_dequeue(&new_queue,&sockfd);
if (rc != 0) {
printf("error! dequeue of a client's sockfd from the shared queue failed: %d\n",rc);
}
if(cipher(sockfd,key_fd)!=0){
printf("chipher did not work");
exit(1);
}
}
printf("worker %d finish\n",j);
close(key_fd);
pthread_exit((void*) &key_fd);
}
int cipher(int sockfd,int key_fd){
int keyFileFD, numberOfBytes,loop,n,key_num,totalsent,nsent,i;
char inputBuffer[262144], keyBuffer[262144],outputBuffer[262144];
if(lseek(key_fd,0,SEEK_SET) == -1){
printf("lseek function failed %s\n", strerror(errno));
return errno;
}
while (1) {
n = read(sockfd, inputBuffer, sizeof(inputBuffer));
if(n < 0){
if(errno ==EPIPE || errno == ENOTCONN || errno == ECONNRESET) {
printf("111");
close(sockfd);
return 0;
}
else{
printf("Read error: %s\n", strerror(errno));
close(sockfd);
return 0;
}
}
key_num=read(key_fd, keyBuffer, n);
if (key_num < 0) {
printf("Error reading file: %s\n", strerror(errno));
return errno;
}
while (key_num<n) {
if(lseek(key_fd,0,SEEK_SET) == -1) {
/*
*error
*/
printf("lseek function failed %s\n", strerror(errno));
return errno;
}
int cont=read(key_fd, keyBuffer+key_num, n-key_num);
if (cont == -1) {
printf("Error reading file: %s\n", strerror(errno));
return errno;
}
key_num=key_num+cont;
}
for(i=0;i<n;i++){
outputBuffer[i] = (inputBuffer[i] ^ keyBuffer[i]);
}
if(write(sockfd, outputBuffer,n)<0) {
if(errno ==EPIPE || errno == ENOTCONN || errno == ECONNRESET) {
close(sockfd);
return 0;
} else{
printf("Read error: %s\n", strerror(errno));
close(sockfd);
return 0;
}
}
close(sockfd);
}
return 0;
}
int main(int argc, char *argv[]) {
int base_sockfd, new_sockfd,i, rc, keyFileFD, num_of_workers,addrsize_1,addrsize_2;
struct sockaddr_in serv_addr, client_addr;
char* key_path = argv[3];
addrsize_1 = sizeof(struct sockaddr);
num_of_workers = atoi(argv[1]);
if(argc!=4){
printf("number of args is not 4: %s\n",strerror(errno));
return errno;
}
if(access(key_path, R_OK)<0){
printf("Key file does not exist or the file is not accessible: %s\n",strerror(errno));
return errno;
}
/*init data structures*/
rc = init_queue(&new_queue,2*num_of_workers);
if (rc!=0) {
printf("error! shared queue init failed\n");
return 1;
}
pthread_t threads[num_of_workers];
/*create workers*/
for (i = 0; i < num_of_workers; i++) {
rc = pthread_create(&threads[i], NULL, worker_thread, (void*) key_path);
if (rc != 0) {
printf("error! pthread_create() failed: %d\n", rc);
return 1;
}
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(atoi(argv[2])); // short, network byte order
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//INADDR_ANY;
if ((base_sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
printf("error! socket() failed: %s\n", strerror(errno));
return errno;
}
if (bind(base_sockfd, (struct sockaddr *)&serv_addr, addrsize_1) < 0) {
printf("error! bind() failed: %s\n", strerror(errno));
close(base_sockfd);
return errno;
}
addrsize_2 = sizeof(struct sockaddr_in);
if (listen(base_sockfd,SOMAXCONN) < 0) {
printf("error! listen() failed: %s\n", strerror(errno));
return errno;
}
while(1){
if ( (new_sockfd = accept(base_sockfd, (struct sockaddr*)&client_addr, &addrsize_2)) <= 0) {
printf("error! accept() failed: %s\n", strerror(errno));
close(base_sockfd);
return errno;
}
/*we have a new valid client sockfd, so enqueue it*/
rc = queue_enqueue(&new_queue, new_sockfd);
if (rc!= 0) {
printf("error! enqueue to shared queue failed withe value:%d\n",rc);
return 1;
}
}
/*clean up and close resources*/
rc=free_queue(&new_queue);
if(rc!=0)
printf("error! free queue failed with value:%d\n",rc);
return 1;
//close(base_sockfd);
/*exit gracefully*/
}
queue:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
typedef struct queue {
int *arr;
int capacity;
int size;
int in;
int out;
pthread_mutex_t mutex;
pthread_cond_t cond_full;
pthread_cond_t cond_empty;
} queue_t;
int queue_enqueue(queue_t *queue, int value) {
int rc;
rc = pthread_mutex_lock(&(queue->mutex));
if(rc!=0){
return rc;
}
while (queue->size == queue->capacity) {
pthread_cond_wait(&(queue->cond_full), &(queue->mutex));
}
queue->arr[queue->in] = value;
++ queue->size;
++ queue->in;
queue->in %= queue->capacity;
rc = pthread_mutex_unlock(&(queue->mutex));
if(rc!=0){
return rc;
}
rc = pthread_cond_signal(&(queue->cond_empty));
if(rc!=0){
return rc;
}
}
int queue_dequeue(queue_t *queue,int *value){
int rc;
rc = pthread_mutex_lock(&(queue->mutex));
if(rc!=0){
return rc;
}
while (queue->size == 0){
pthread_cond_wait(&(queue->cond_empty), &(queue->mutex));
}
*value = queue->arr[queue->out];
-- queue->size;
++ queue->out;
queue->out %= queue->capacity;
rc = pthread_mutex_unlock(&(queue->mutex));
if(rc!=0){
return rc;
}
rc = pthread_cond_signal(&(queue->cond_full));
return rc;
}
int init_queue(queue_t *new_queue,int cnt) {
int rc;
new_queue->capacity = cnt;
new_queue->arr = malloc(sizeof(cnt)*sizeof(int));
if (new_queue->arr== NULL) {
return -1;
}
new_queue->size = 0;
new_queue->in = 0;
new_queue->out = 0;
//init shared queue lock (mutex)
rc = pthread_mutex_init(&(new_queue->mutex), NULL);
if (rc != 0) {
return rc;
}
//init shared queue conditions variable
rc = pthread_cond_init(&(new_queue->cond_full), NULL);
if (rc != 0) {
return rc;
}
rc = pthread_cond_init(&(new_queue->cond_empty), NULL);
if (rc != 0) {
return rc;
}
}
int free_queue(queue_t *queue_to_kill) {
int rc;
rc = pthread_mutex_destroy(&(queue_to_kill->mutex));
if (rc) {
return rc;
}
rc = pthread_cond_destroy(&(queue_to_kill->cond_empty));
if (rc) {
return rc;
}
rc = pthread_cond_destroy(&(queue_to_kill->cond_full));
if (rc) {
return rc;
}
}
client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
int connectToHostname(int sock, char* hostname, char* port);
int main(int argc, char* argv[]){
int sock;
char* hostname;
char* port;
/* place default port if required*/
if(argc < 3)
{
port = "42666";
}
else
{
port = argv[2];
}
/* place default hostname if required*/
if(argc == 1)
{
hostname = "localhost";
}
else
{
hostname = argv[1];
}
/* open TCP socket with IPv4*/
if((sock = socket(PF_INET, SOCK_STREAM, 0))<0)
{
perror("Could not open socket");
exit(errno);
}
int fd = -1;
int fd2 = -1;
if(argc >= 4)
{
fd = open(argv[3], O_WRONLY|O_CREAT|O_TRUNC, 0666);
}
if(argc >= 5)
{
fd2 = open(argv[4], O_RDONLY, 0);
}
connectToHostname(sock, hostname, port);
char buf[100];
while(1)
{
if(fd2 <0)
{
scanf("%99s",buf);
send(sock, buf, strlen(buf), 0);
}
else
{
int stupid = read(fd2, buf, 99);
if(stupid == 0)
{
close(sock);
exit(0);
}
send(sock, buf, stupid, 0);
}
int sz = recv(sock, buf, 99, 0);
buf[100] = '\0';
if(fd< 0)
{
printf("%s\n", buf);
}
else
{
write(fd, buf, sz);
}
}
}
int connectToHostname(int sock, char* hostname, char* port)
{
int rv;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in *h;
struct sockaddr_in dest_addr;
/* server addr is IPv4*/
dest_addr.sin_family = AF_INET;
/* write server port*/
dest_addr.sin_port = htons((short)strtol(port, NULL,10));
/* zero out hints (since garbage is bad)*/
memset(&hints, 0, sizeof(hints));
/* we want IPv4 address and TCP*/
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
/* try get address info*/
if((rv = getaddrinfo(hostname, port, &hints, &servinfo)) != 0)
{
fprintf(stderr, "Error getting address info: %s\n", gai_strerror(rv));
exit(1);
}
p = servinfo;
while(p!= NULL)
{
/* put last address into sent pointer*/
h = (struct sockaddr_in *)p->ai_addr;
dest_addr.sin_addr = h->sin_addr;
if(connect(sock, (struct sockaddr*)(&dest_addr), sizeof(struct sockaddr)) == 0)
break;/* if connection succesfull*/
p = p->ai_next;
}
freeaddrinfo(servinfo);
if(p == NULL)
{
/*We didnt find a host*/
perror("Could not connect to server");
exit(errno);
}
return 0;
}
i used this script to test it:
echo niv > key_file
echo is > read_file_b
echo thethethethethethethethethethe > read_file_c
echo se > read_file_d
echo rse > read_file_e
echo rse > read_file_f
echo aaaaaaa > write_file_a
echo bbbbbbb > write_file_b
echo ccccccc > write_file_c
echo ddddddd > write_file_d
echo ddddddd > write_file_e
echo ddddddd > write_file_f
gcc setos_server.c -pthread -o setos_server
./setos_server 3 2 key_file &
sleep 0.1
#printf "\n\n"
gcc client.c -pthread -o client
./client 127.0.0.1 2 write_file_a read_file_a &
./client 127.0.0.1 2 write_file_b read_file_b &
./client 127.0.0.1 2 write_file_c read_file_c &
./client 127.0.0.1 2 write_file_d read_file_d &
./client 127.0.0.1 2 write_file_e read_file_e &
./client 127.0.0.1 2 write_file_f read_file_f &
./client 127.0.0.1 2 final_file_a write_file_a &
./client 127.0.0.1 2 final_file_b write_file_b &
./client 127.0.0.1 2 final_file_c write_file_c &
./client 127.0.0.1 2 final_file_d write_file_d &
./client 127.0.0.1 2 final_file_e write_file_e &
./client 127.0.0.1 2 final_file_f write_file_f &
sleep 2
pkill setos_server
when read_file_a is a big file (more then 10000 chars).
thank you for your help.
One too many close()
while (1) {
n = read(sockfd, inputBuffer, sizeof(inputBuffer));
if(n < 0){
....
}
close(sockfd);
}
kills the socket after the very first read().
PS: shorter functions and correct formatting makes it very easy to spot.
I have write a programming about transfer files from server to client.But problem is that I can only transfer 2G files if file is bigger than 2G ,only 2G transfer successfully.
client
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <math.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAXLINE 1000
#define SA struct sockaddr
typedef struct
{
int oft;
int len;
char data[MAXLINE];
}Mem;
Mem Dat;
int main(int argc,char *argv[])
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
int complete;
struct sockaddr_in cli;
ssize_t recv_l,send_l;
size_t block_len;
socklen_t len;
char buf[MAXLINE];
char filename[MAXLINE];
FILE *fp;
bzero(&cli,sizeof(cli));
cli.sin_family = AF_INET;
if (argv[1] == NULL)
argv[1] = "172.16.42.22";
cli.sin_port = htons(5001);
inet_pton(AF_INET,argv[1],&cli.sin_addr.s_addr);
bind(sockfd,(struct sockaddr*)&cli,sizeof(cli));
if (connect(sockfd,(SA*)&cli,sizeof(cli)) == -1)
{
perror("connect");
close(sockfd);
exit(1);
}
//接收文件名列表
while((recv_l = recv(sockfd,buf,sizeof(buf),0)) > 0)
{
buf[recv_l] = '\0';
fputs(buf,stdout);
if(strcmp(buf+recv_l-5,"name\n") == 0)
break;
}
// exit(0);
bzero(filename,sizeof(filename));
while(fgets(filename,sizeof(filename),stdin) != NULL)
// while(gets(filename) != NULL)
{
int i = 0;
for(i = strlen(filename) - 1;i >= 0;i --)
if(filename[i] == '\n'){
filename[i] = '\0';
break;
}
send_l = send(sockfd,filename, strlen(filename),0);
recv_l = recv(sockfd,buf, sizeof(buf),0);
buf[recv_l] = '\0';
puts(buf);
if (strcmp(buf,"success") == 0)
break;
fputs(buf,stdout);
}
puts("filename send success");
//接收文件
if ((fp = fopen(filename,"wb")) == NULL)
{
perror("fopen");
exit(1);
}
while((recv_l = recv(sockfd,&Dat,sizeof(Dat),MSG_WAITALL)))
{
if (recv_l < 0){
perror("recv");
exit(1);
}
fwrite(Dat.data,sizeof(char),Dat.len,fp);
}
puts("file receive success");
fclose(fp);
close(sockfd);
return 0;
}
server
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <math.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAXLINE 1000
#define SA struct sockaddr
typedef struct
{
int oft;
int len;
char data[MAXLINE];
}Mem;
Mem Dat;
long long sum = 0;
int sendall(int sockfd, void *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n;
while(total < *len) {
n = send(sockfd, buf+total, bytesleft, 0);
sum += n;
if(sum >= 1073741824){
puts("1G");
sum = 0;
}
if (n != bytesleft) return -1;
if (n == -1) {
break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
int main(int argc,char *argv[])
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
socklen_t len;
size_t block_len;
int complete;
ssize_t send_l,recv_l;
struct sockaddr_in serv,cli;
char buf[MAXLINE];
char filename[100];
FILE *fp;
bzero(&serv,sizeof(serv));
serv.sin_family = AF_INET;
if (argv[1] == NULL)
argv[1] = "5001";
serv.sin_port = htons(atoi(argv[1]));
serv.sin_addr.s_addr = htonl(0);
bind(sockfd,(SA*)&serv,sizeof(serv));
listen(sockfd,5);
// for( ; ; )
{
len = sizeof(cli);
complete = accept(sockfd,(SA*)&cli,&len);
//发送文件名列表
fp = popen("ls","r");
while( fgets(buf,MAXLINE,fp) != NULL)
{
send(complete,buf,strlen(buf),0);
}
strcpy(buf,"input file name\n");
send(complete,buf, strlen(buf),0);
puts("send list success");
pclose(fp);
//exit(0);
//获取文件名
while( (recv_l = recv(complete,filename,sizeof(filename),0) ) > 0)
{
filename[recv_l] = '\0';
if ((fp = fopen(filename,"rb")) == NULL)
{
strcpy(buf,"filename error please input again");
puts("filename error");
send(complete,buf,strlen(buf),0);
}else{
puts("get filename success");
break;
}
}
//文件名对了
strcpy(buf,"success");
send(complete,buf,strlen(buf),0);
puts("get correct filename");
//传文件
int all = 0;
long long sa = 0;
int len = sizeof(Dat);
while((block_len = fread(Dat.data,sizeof(char),MAXLINE,fp)) > 0)
{
Dat.len = block_len;
if (sendall(complete,&Dat,&len) < 0){
puts("send error");
exit(1);
}
// if (send(complete,&Dat ,sizeof(Dat),0) < 0)
// {
// perror("send");
// exit(1);
// }
}
printf("%lld\n",sum);
printf("%s Tranfer finished\n",filename);
fclose(fp);
close(complete);
}
return 0;
}
on 32 bit systems, the maximum file size is 2 GB by default.
you can compile your program with the switch -D_FILE_OFFSET_BITS=64 to create files larger than 2 GB or use 64 bit.
I got a Unix shell in a server which should send the output the the client and then be printed out. I have tried several different methods to get the full output but i only get 3-5 letters even though I use a while-loop in recv which should be able to receive everything.
The server prints out the whole output but the client doesn't receive the whole data.
Server code:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#define SOCK_PATH "echo_socket"
#define ORDLANGD 30
#define die(e) do { fprintf(stderr, e); exit(EXIT_FAILURE); } while (0);
void byt(char *foo);
void lasIn(char *a1, char *argv[]);
static void pSigHandler(int signo){
switch (signo) {
case SIGTSTP:
printf("TSTP");
fflush(stdout);
break;
}
}
int main(void)
{
int s, s2, t, len, newsockfd;
struct sockaddr_un local, remote;
char str[100];
char *argv[7];
char foo[4096];
int link[2];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
local.sun_family = AF_UNIX;
strcpy(local.sun_path, SOCK_PATH);
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(s, (struct sockaddr *)&local, len) == -1) {
perror("bind");
exit(1);
}
if (listen(s, 5) == -1) {
perror("listen");
exit(1);
}
struct sigaction psa;
psa.sa_handler = pSigHandler;
sigaction(SIGTSTP, &psa, NULL);
for(;;) {
int done, n;
printf("Waiting for a connection...\n");
t = sizeof(remote);
if ((s2 = accept(s, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
pid_t pid;
pid = fork();
if (pid < 0)
{
perror("ERROR on fork");
exit(1);
}
if (pid == 0)
{
/* This is the client process */
close(s);
done = 0;
do {
n = recv(s2, str, 100, 0);
if (n <= 0) {
if (n < 0) perror("recv");
done = 1;
}
lasIn(str, argv);
if ((strcmp(argv[0], "exit")) == 0){
exit(0);
}
else if ((strcmp(argv[0], "cd")) == 0){
if ((chdir(argv[1])) != 0){
printf("Gar inte att byta katalog\n");
}
}
pid_t pid;
if (pipe(link)==-1)
die("pipe");
if ((pid = fork()) == -1)
die("fork");
if(pid == 0) {
dup2 (link[1], STDOUT_FILENO);
close(link[0]);
execvp(argv[0], argv);
sleep (1);
exit(0);
} else {
close(link[1]);
read(link[0], foo, sizeof(foo));
printf("\n\n%s\n\n", foo);
wait(NULL);
}
if (!done)
{
if (send(s2, foo, n, 0) < 0) {
perror("send");
done = 1;
}
}
} while (!done);
}
else
{
close(s2);
}
}
return 0;
}
void lasIn(char *a1, char *argv[]){
int i;
argv[0] = strtok(a1, " \n");
for(i = 1; i < 6; i = i++) {
argv[i] = strtok(NULL, " \n");
if (argv[i] == NULL)
break;
}
argv[6] = NULL;
}
Client code:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#define SOCK_PATH "echo_socket"
int main(void)
{
int s, t, len;
struct sockaddr_un remote;
char str[100];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
printf("Trying to connect...\n");
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, SOCK_PATH);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(s, (struct sockaddr *)&remote, len) == -1) {
perror("connect");
exit(1);
}
printf("Connected.\n");
while(printf("> "), fgets(str, 100, stdin), !feof(stdin)) {
if (send(s, str, strlen(str), 0) == -1) {
perror("send");
exit(1);
}
while(1)
{
memset(str ,0 , 100); //clear the variable
if(recv(s , str , 100 , 0) < 0)
{
break;
}
else
{
printf("%s" , str);
break;
}
}
}
close(s);
return 0;
}
Given that you are getting some, not all of your expected traffic, perhaps one potential problem is the two break; statments in your code section:
while(1)
{
memset(str ,0 , 100); //clear the variable
if(recv(s , str , 100 , 0) < 0)
{
break;//here
}
else
{
printf("%s" , str);
break;//and here
}
}
The first time in, it will either break out of the while loop in one or the other branches, regardless of whether there is more data.
You might consider two additional things:
1) using an alternate call structure. Something like:
while(recv(s , str , 100 , 0) > 0)
{
...
}
//do some error checking here
2) put a small (fraction of a second) delay between leaving a successful send(,,,); and calling recv(,,,).
EDIT example of using terminating character with sockets
numBytesReceived = recv(irdaCommSocket, recvBuf, readBufsize, 0);
while(strstr(recvBuf, "%") == NULL)//uniques terminating character (use anything, including `\n`)
{
if (numBytesReceived < 0) return WSAGetLastError();//windows specific, change error handling for linux
strncpy(bufptr, recvBuf, readBufsize);
*pNumBytes += numBytesReceived;
numBytesReceived = recv(irdaCommSocket, recvBuf, readBufsize, 0);
}