I'm using TCP_REPAIR to create a pair of already-connected sockets that talk to each other without actually going through the TCP connect flow.
I've tried to use the ideas in LWN for connection repair and their soccr library, but unfortunately, no matter what I do, I always get an ECONNRESET error the moment I try to write data to any of the sockets.
Here's an example of what I've tried:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/socket.h>
#include <netinet/tcp.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdlib.h>
#include <errno.h>
struct tcp {
char *addr;
uint32_t port;
};
int createSocket(struct tcp src, struct tcp dst) {
int sk, yes = 1;
struct sockaddr_in addr;
sk = socket(AF_INET, SOCK_STREAM, 0);
if (sk < 0) {
printf("Cannot create socket\n");
return -1;
}
if (setsockopt(sk, SOL_TCP, TCP_REPAIR, &yes, sizeof(yes))) {
printf("Cannot set TCP_REPAIR\n");
return -1;
}
if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
printf("Cannot set SO_REUSEADDR\n");
return -1;
}
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(src.port);
if (inet_pton(AF_INET, src.addr, &(addr.sin_addr)) < 0) {
printf("Error converting source host:port to binary\n");
return -1;
}
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr))) {
printf("Cannot bind to source port\n");
return -1;
}
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(dst.port);
if (inet_pton(AF_INET, dst.addr, &(addr.sin_addr)) < 0) {
printf("Error converting destination host:port to binary\n");
return -1;
}
if (connect(sk, (struct sockaddr *) &addr, sizeof(addr))) {
printf("Cannot bind to remote port\n");
return -1;
}
int no = 0;
if (setsockopt(sk, SOL_TCP, TCP_REPAIR, &no, sizeof(no))) {
printf("Cannot set TCP_REPAIR\n");
return -1;
}
return sk;
}
int main(int argc, char **argv) {
struct tcp tcp[2] = {
{"127.0.0.1", 17000},
{"127.0.0.1", 34000}
};
int source_socket = createSocket(tcp[0], tcp[1]);
printf("Source socket created: %d \n",source_socket);
int dest_socket = createSocket(tcp[1], tcp[0]);
printf("Destination socket created: %d \n",dest_socket);
if (source_socket < 0 || dest_socket < 0)
return -1;
char* message = "Hello world";
ssize_t written = write(dest_socket, message, strlen(message)); // ECONNRESET error
if (written < 0) {
printf("Error writing to socket %d\n",errno);
return -1;
}
printf("%ld bytes written\n",written);
char buffer[1024];
ssize_t bytesRead = read(dest_socket, buffer, sizeof(buffer)-1);
printf("Bytes read %ld\n",bytesRead);
buffer[bytesRead] = 0;
printf("Message read: %s\n",buffer);
printf("Finished %d %d \n",source_socket,dest_socket);
return 0;
}
And the output is
Source socket created: 3
Destination socket created: 4
Error writing to socket 104
I get the same result (Connection reset by peer error) if I use the soccr library:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/socket.h>
#include <netinet/tcp.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdlib.h>
#include <errno.h>
#include "./soccr.h"
struct tcp {
char *addr;
uint32_t port;
uint32_t seq;
uint16_t mss_clamp;
uint16_t wscale;
};
int createSocket(struct tcp src, struct tcp dst) {
int sk, yes = 1;
union libsoccr_addr src_addr, dst_addr;
struct libsoccr_sk_data data = {};
struct libsoccr_sk *so;
data.state = TCP_ESTABLISHED;
data.inq_seq = dst.seq;
data.outq_seq = src.seq;
sk = socket(AF_INET, SOCK_STREAM, 0);
if (sk < 0) {
printf("Cannot create socket. Errno %d\n",errno);
return -1;
}
so = libsoccr_pause(sk);
if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
printf("Cannot set socket options. Errno %d\n",errno);
return -1;
}
src_addr.v4.sin_family = AF_INET;
src_addr.v4.sin_port = htons(src.port);
if (inet_pton(AF_INET, src.addr, &src_addr.v4.sin_addr) != 1) {
printf("Cannot convert source host:port to binary. Errno %d\n",errno);
return -1;
}
dst_addr.v4.sin_family = AF_INET;
dst_addr.v4.sin_port = htons(dst.port);
if (inet_pton(AF_INET, dst.addr, &(dst_addr.v4.sin_addr)) != 1) {
printf("Cannot convert destination host:port to binary. Errno %d\n",errno);
return -1;
}
libsoccr_set_addr(so, 1, &src_addr, 0);
libsoccr_set_addr(so, 0, &dst_addr, 0);
data.snd_wscale = src.wscale;
data.rcv_wscale = dst.wscale;
data.mss_clamp = src.mss_clamp;
data.opt_mask = TCPI_OPT_WSCALE | TCPOPT_MAXSEG;
if (libsoccr_restore(so, &data, sizeof(data)) < 0) {
printf("Cannot apply restore options. Errno %d\n",errno);
return -1;
}
libsoccr_resume(so);
return sk;
}
int main(int argc, char **argv) {
struct tcp tcp[2] = {
{"127.0.0.1", 17000, 5000000, 1460, 7},
{"127.0.0.1", 34000, 6000000, 1460, 7}
};
int source_socket = createSocket(tcp[0], tcp[1]);
printf("Source socket created: %d \n",source_socket);
int dest_socket = createSocket(tcp[1], tcp[0]);
printf("Destination socket created: %d \n",dest_socket);
if (source_socket < 0 || dest_socket < 0)
return -1;
char* message = "Hello world";
ssize_t written = write(source_socket, message, strlen(message));
if (written < 0) {
printf("Error writing to socket %d\n",errno);
return -1;
}
printf("%ld bytes written\n",written);
char buffer[1024];
ssize_t bytesRead = read(dest_socket, buffer, sizeof(buffer)-1);
printf("Bytes read %ld\n",bytesRead);
buffer[bytesRead] = 0;
printf("Message read: %s\n",buffer);
printf("Finished\n");
return 0;
}
Any ideas about what I might be doing wrong here?
Related
I met a strange question, When I run a TCP program manually(./tcpServDemo),Tcp Server program Can receive more than 5000 client connections, But When I running tcpServerDemo in the background(systemctl start tcpServDemo.service),It can only receive more than 900 client connections,
when I debugging, I found TCP recv-Q queue is full. I modified the TCP parameters(net.core.somaxconn = 65500 net.ipv4.tcp_max_syn_backlog = 409600),But it didn't work
I've been debugging for several days. I really don't know where the problem is?Who can help me,
thanks for everyone!
OS: CentOS 7.9
tcpClient.c:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
//#define SERVPORT 8088
int ServPort;
char ServerIP[32];
pthread_mutex_t lock;
int count;
void *cTcpConn(void *arg) {
usleep(2000);
int sockfd,sendbytes;
struct sockaddr_in serv_addr;//需要连接的服务器地址信息
memset(&serv_addr, 0, sizeof(struct sockaddr_in));
//1.创建socket
//AF_INET 表示IPV4
//SOCK_STREAM 表示TCP
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
printf("socket create failed.");
return NULL;
}
//填充服务器地址信息
serv_addr.sin_family = AF_INET; //网络层的IP协议: IPV4
serv_addr.sin_port = htons(ServPort); //传输层的端口号
serv_addr.sin_addr.s_addr = inet_addr(ServerIP); //网络层的IP地址: 实际的服务器IP地址
//2.发起对服务器的连接信息
//三次握手,需要将sockaddr_in类型的数据结构强制转换为sockaddr
if((connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr))) < 0) {
printf("connect failed!\n");
close(sockfd);
return NULL;
} else {
pthread_mutex_lock(&lock);
count++;
pthread_mutex_unlock(&lock);
printf("connect successful! count:%d\n", count);
}
#if 0
//3.发送消息给服务器端
if((sendbytes = send(sockfd,"hello",5,0)) < 0) {
perror("send");
exit(1);
}
#endif
while(1) {
sleep(10);
}
//4.关闭
close(sockfd);
return NULL;
}
int main(int argc, char **argv) {
if (argc != 3) {
printf("Usage: %s ServerIP ServerPort\n", argv[0]);
return 0;
}
strncpy(ServerIP, argv[1], sizeof(ServerIP) - 1);
ServPort = atoi(argv[2]);
int i;
pthread_t pid;
for (i = 0; i < 8000; i++) {
usleep(10000);
if(0 != pthread_create(&pid, NULL, cTcpConn, NULL)) {
printf("thread create failed.\n");
}
}
while (1) {
sleep(10);
}
return 0;
}
tcpServDemo.c:
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int main() {
const int EVENTS_SIZE = 4096;
char buff[1024];
int eNum;
int socketFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in sockAddr;
sockAddr.sin_port = htons(8088);
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = htons(INADDR_ANY);
if (bind(socketFd, (struct sockaddr *) &sockAddr, sizeof(sockAddr)) == -1) {
return -1;
}
if (listen(socketFd, 10) == -1) {
return -1;
}
int eFd = epoll_create(1);
struct epoll_event epev;
epev.events = EPOLLIN;
epev.data.fd = socketFd;
epoll_ctl(eFd, EPOLL_CTL_ADD, socketFd, &epev);
int i;
int count = 0;
struct epoll_event events[EVENTS_SIZE];
while (1) {
eNum = epoll_wait(eFd, events, EVENTS_SIZE, -1);
if (eNum == -1) {
return -1;
}
for (i = 0; i < eNum; i++) {
if (events[i].data.fd == socketFd) {
if (events[i].events & EPOLLIN) {
struct sockaddr_in cli_addr;
socklen_t length = sizeof(cli_addr);
int fd = accept(socketFd, (struct sockaddr *) &cli_addr, &length);
if (fd > 0) {
count++;
epev.events = EPOLLIN | EPOLLET;
epev.data.fd = fd;
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) {
continue;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
continue;
}
epoll_ctl(eFd, EPOLL_CTL_ADD, fd, &epev);
printf("client on line fd:%d-count:%d\n", fd, count);
} else {
printf("accept failed.\n, fd:%d-errno:%d-strerror:%s\n", fd, errno, strerror(errno));
}
}
} else {
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) {
epoll_ctl(eFd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
close(events[i].data.fd);
}
}
}
}
}
/usr/lib/systemd/system/tcpServDemo.service:
[Unit]
Description= application service monitor daemon
After=network.target
[Service]
User=root
Type=forking
ExecStart=/var/workstation/testcode/C-Code/tcpServDemo
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=1s
[Install]
WantedBy=multi-user.target graphic.target
You were running out of file descriptors. accept() would have returned -1 and set errno to EMFILE. It would have been helpful to share that error message with us. You raise the (soft) file descriptor limit by either
setting LimitNOFILESoft your service file to suitable higher value (see systemd.exec(5)), or
calling setrlimit(RLIMIT_NOFILE, ...) with a higher value for rlim_cur less than rlimit_max. It's pretty normal for servers to set their rlimit_cur to the rlimit_max retrieved from getrlimit(RLIMIT_NOFILE, ...) so you can tweak resource usage (in this case number of file descriptors) externally.
I wrote my first socket program today. I based it on some examples from the man pages and the web.
server.c:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#define ALX_NO_PREFIX
#include <libalx/base/compiler/size.h>
#include <libalx/base/errno/error.h>
#define SERVER_PORT "30002"
#define SERVER_IP "127.0.0.1"
int tcp_server_open (const char *server_port)
{
struct protoent *tcp;
int sd;
struct addrinfo hint = {0};
struct addrinfo *addrs;
int status;
tcp = getprotobyname("tcp");
if (!tcp)
return -EINVAL;
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = tcp->p_proto;
hint.ai_flags = AI_PASSIVE;
status = getaddrinfo(NULL, server_port, &hint, &addrs);
if (status) {
perrorx("getaddrinfo() failed");
return -labs(status);
}
for (struct addrinfo *addr = addrs; addr; addr = addr->ai_next) {
sd = socket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol);
if (sd < 0) {
perrorx("socket() failed");
continue;
}
if (!bind(sd, addr->ai_addr, addr->ai_addrlen)) {
perrorx("binded!");
break;
}
close(sd);
sd = -1;
perrorx("bind() failed");
}
freeaddrinfo(addrs);
perrorx("break");
if (sd < 0)
return -errno;
perrorx("open!");
return sd;
}
int main (void)
{
int sd;
char buf[BUFSIZ];
struct sockaddr_storage cli_addr = {0};
socklen_t cli_addr_len;
ssize_t n;
int s;
int status;
char host[NI_MAXHOST];
char service[NI_MAXSERV];
status = EXIT_FAILURE;
sd = tcp_server_open(SERVER_PORT);
if (sd < 0) {
perrorx("tcp_server_open(ROBOT_PORT);");
goto out;
}
while (true) {
cli_addr_len = sizeof(cli_addr);
n = recvfrom(sd, buf, ARRAY_SIZE(buf), 0,
(struct sockaddr *)&cli_addr, &cli_addr_len);
if (n < 0) {
//if (errno != 107)
perrorx("no msg");
continue;
}
s = getnameinfo((struct sockaddr *)&cli_addr, cli_addr_len,
host, NI_MAXHOST, service,
NI_MAXSERV, NI_NUMERICSERV);
if (!s) {
printf("Received %zd bytes from %s:%s\n", n, host, service);
} else {
perrorx("getnameinfo() failed");
fprintf(stderr, "getnameinfo(): %s\n", gai_strerror(s));
}
printf("%*s\n", (int)ARRAY_SSIZE(buf), buf);
if (sendto(sd, buf, n, 0, (struct sockaddr *)&cli_addr, cli_addr_len) != n)
perrorx("sendto() failed");
printf("%s\n", buf);
printf("Enter msg:\n");
fgets(buf, ARRAY_SIZE(buf), stdin);
n = write(sd, buf, strlen(buf));
if (n < 0) {
perrorx("write() failed");
goto out;
}
}
status = EXIT_SUCCESS;
out:
perrorx("out");
return close(sd) || status;
}
client.h:
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#define ALX_NO_PREFIX
#include <libalx/base/compiler/size.h>
#include <libalx/base/errno/error.h>
#define SERVER_PORT "30002"
#define SERVER_IP "127.0.0.1"
int tcp_client_open (const char *server_ip, const char *server_port)
{
struct protoent *tcp;
int sd;
//struct addrinfo hint = {0};
struct addrinfo *addrs;
int status;
tcp = getprotobyname("tcp");
if (!tcp) {
perrorx("getprotobyname() failed");
return -EINVAL;
}
//hint.ai_family = AF_INET;
//hint.ai_socktype = SOCK_STREAM;
//hint.ai_protocol = tcp->p_proto;
status = getaddrinfo(server_ip, server_port, /*&hint*/NULL, &addrs);
if (status) {
perrorx("getaddrinfo() failed");
return -labs(status);
}
for (struct addrinfo *addr = addrs; addr; addr = addr->ai_next) {
sd = socket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol);
if (sd < 0) {
perrorx("socket() failed");
break;
}
if (!connect(sd, addr->ai_addr, addr->ai_addrlen)) {
perrorx("connected!");
break;
}
close(sd);
sd = -1;
perrorx("connect() failed");
}
freeaddrinfo(addrs);
perrorx("break");
if (sd < 0)
return -errno;
perrorx("open!");
return sd;
}
int main (void)
{
int sd;
char buf[BUFSIZ];
ssize_t n;
int status;
status = EXIT_FAILURE;
sd = tcp_client_open(SERVER_IP, SERVER_PORT);
if (sd < 0) {
perrorx("tcp_client_open() failed");
goto out;
}
printf("Enter msg:\n");
fgets(buf, ARRAY_SIZE(buf), stdin);
n = write(sd, buf, strlen(buf));
if (n < 0) {
perrorx("write() failed");
goto out;
}
memset(buf, 0, ARRAY_SIZE(buf));
n = read(sd, buf, ARRAY_SIZE(buf));
if (n < 0) {
perrorx("read() failed");
goto out;
}
printf("%*s\n", (int)ARRAY_SSIZE(buf), buf);
status = EXIT_SUCCESS;
out:
perrorx("out");
return close(sd) || status;
}
void perrorx(const char *msg); is a wrapper around perror but also prints the file, line and function name.
The server outputs the following:
./server:
server.c:50:
tcp_server_open():
binded!
E0 - Success
./server:
server.c:59:
tcp_server_open():
break
E0 - Success
./server:
server.c:64:
tcp_server_open():
open!
E0 - Success
and then loops in the following message (if I uncomment the test if (errno != 107), it doesn't print anything) (trying to connect the server doesn't affect it):
./server:
server.c:97:
main():
no msg
E107 - Transport endpoint is not connected
And I have to kill it with ^C (of course after the client exits).
The client outputs the following:
./client:
client.c:56:
tcp_client_open():
connect() failed
E111 - Connection refused
./client:
client.c:50:
tcp_client_open():
connected!
E111 - Connection refused
./client:
client.c:59:
tcp_client_open():
break
E111 - Connection refused
./client:
client.c:64:
tcp_client_open():
open!
E111 - Connection refused
Enter msg:
asd
./client:
client.c:95:
main():
read() failed
E111 - Connection refused
./client:
client.c:102:
main():
out
E111 - Connection refused
What is the problem? I have almost zero knowledge about socckets.
I'm working on a TCP client server program which is supposed to support several clients using threads.
The socket creation, connection, bind and accept work as expected since I receive no errors when running the code.
However whenever I try to read() from the server the code enters an infinite loop and nothing happens.
I tried writing from the server first and the write result was written to the server's terminal.
Client code:
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h>
#define FILE_ADDR "/dev/urandom"
int main(int argc, char *argv[]) {
//Get command line arguments
unsigned int port = atoi(argv[2]);
int length = atoi(argv[3]); //Number of bytes to read
char* buffer = malloc(length * sizeof(char)); //Buffer to hold data read from file
char* recvBuf = malloc(10 * sizeof(char)); // Buffer to hold response from server
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in serv_addr;
int sockfd = -1;
//int rv;
//char ip[100];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo);
if (rv != 0) {
perror("getaddrinfo error\n");
exit(1);
}
for (p = servinfo; p != NULL; p = p->ai_next) {
//Initialize socket
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd < 0)
continue;
//Initialize connection
rv = connect(sockfd, p->ai_addr, (socklen_t) p->ai_addrlen);
if (rv == 0)
break;
close(sockfd);
sockfd = -1;
}
// inet_aton(ip, &h.sin_addr);
freeaddrinfo(servinfo);
//Open file for reading
FILE *fp;
fp = fopen(FILE_ADDR, "r");
if (fp == NULL) {
perror("Error in file open\n");
}
printf("file opened\n");
size_t numOfbytesRead = fread(buffer, sizeof(char), length, fp);
if (numOfbytesRead != length) {
perror("Error reading from file\n");
}
printf("Buffer is %s\n", buffer);
char* ptr;
unsigned int N = strtoul(argv[3],&ptr,10);
int convertedNum = htonl(N);
if (write(sockfd, &convertedNum, sizeof(unsigned int)) < 0) { //Send number of bytes
perror("error writing to socket");
}
if (write(sockfd, buffer, sizeof(buffer) < 0)) {//Send bytes read from file
perror("error writing to socket");
}
printf("send is done \n");
int bytes_read = read(sockfd, recvBuf, sizeof(recvBuf)); //Recieve response from server
if (bytes_read <= 0) {
perror("Error in recieving result from server\n");
}
unsigned int C = 0;
sprintf(recvBuf[0], "%d", C);
fclose(fp);
printf("# of printable characters: %u\n", C);
exit(0);
free(buffer);
free(recvBuf);
}
Server code:
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h>
#include <pthread.h>
#include <signal.h>
static volatile int keepRunning = 1;
int pcc_total[159];
void intHandler(int dummy) {
keepRunning = 0;
}
void *compute(void *socket_desc) {
int count = 0;
int sock = *(int*) socket_desc;
printf("now will allocate N \n");
int n=0;
if (write(sock, "hi", 2) < 0) { //Send number of bytes
perror("error writing to socket\n");
}
if (read(sock, &n, sizeof(unsigned int)) < 0) {
perror("Error reading from socket\n");
exit(1);
}
int N = ntohl(n);
printf("len is %d\n", N);
char* data = calloc(N, sizeof(char));
int len = read(sock, data, N);
printf("data is %s\n", data);
if (len < 0) {
perror("Error reading from socket\n");
exit(1);
}
for (int i = 0; i < len; i++) {
int tmp = 0;
sprintf(data[i], "%d", tmp);
if (tmp >= 32 & tmp <= 126) {
count++;
__sync_fetch_and_add(&pcc_total[tmp], 1);
}
}
char scount[100];
atoi(count);
write(sock, count, strlen(scount));
free(data);
pthread_exit(NULL);
close(sock);
exit(0);
}
int main(int argc, char *argv[]) {
unsigned int port = atoi(argv[1]);
signal(SIGINT, intHandler);
int socket_desc, client_sock, c, *new_sock;
struct sockaddr_in server, client;
c = sizeof(struct sockaddr_in);
socket_desc = socket( AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1) {
perror("Could not create socket");
exit(1);
}
printf("socket created\n");
memset(&server, 0, c);
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(port);
if (0 != bind(socket_desc, (struct sockaddr*) &server, sizeof(server))) {
perror("\n Error : Bind Failed \n");
exit(1);
}
printf("bind created\n");
if (0 != listen(socket_desc, 10)) {
perror("\n Error : Listen Failed \n");
exit(1);
}
printf("listen created\n");
while (keepRunning) {
client_sock = accept(socket_desc, (struct sockaddr *) &client,
(socklen_t*) &c);
if (client_sock < 0) {
perror("\n Error : Accept Failed\n");
exit(1);
}
printf("accept created\n");
pthread_t tid;
new_sock = malloc(100*sizeof(int));
*new_sock = client_sock;
if ((pthread_create(&tid, NULL, compute, (void*) new_sock)) < 0) {
perror("could not create thread\n");
exit(1);
}
printf("thread created\n");
// close socket
close(client_sock);
free(new_sock);
pthread_join(tid, NULL);
}
exit(0);
}
I run the code with the following commands:
gcc -std=c99 -O3 -Wall -o pcc_server pcc_server.c -pthread
gcc -std=gnu99 -O3 -Wall -o pcc_client pcc_client.c
There are a number of problems with your code.
On the client side:
When calling fread(), you need to use "rb" instead of "r".
when calling printf() to output the file data that was actually read, you are not null-terminating buffer, or passing its length to printf(). You need to do so.
You are assigning the return value of htonl() to an int instead of an unsigned int.
when calling write() to send the buffer, you are using sizeof(buffer) when you should be using length or N instead (and why are you using two separate variables to hold the same command-line parameter value?). buffer is a pointer to memory allocated with malloc(), so sizeof(buffer) is the same as sizeof(void*), which is not what you want. Also, you are not even calling write() correctly, because your parenthesis are all wrong (they are correct on the previous write() call when sending convertedNum).
likewise, when calling read() to read the recvBuf, you are using sizeof(recvBuf) when you should be using 10 instead, sicne recvBuf is also a pointer to malloced memory.
you are not reading the "hi" greeting that the server sends to the client upon connection, so you lump in those bytes with the bytes of the following size value of the next message, and thus end up with a corrupted C value.
On the server side:
your compute thread routine sends a "hi" greeting to the client, but it does not use any kind of delimiter, like prefixing the greeting with its length, or terminating it with a line break or null character or other unique character, to separate it from any subsequent data. You should always delimit your messages in some manner.
you are closing the accepted socket and freeing the malloced new_sock as soon as you create a worker thread to handle that client. You are ripping away memory from behind the thread's proverbial back. The thread needs to be the one to close the socket and free the memory when it is done using them, not the accept loop.
The thread does attempt to close the socket (but not free the memory), but after it calls pthread_exit() first, which is wrong. pthread_exit() terminates the calling thread, so it needs to be the last thing that the thread calls (DO NOT call exit()!). In fact, don't even call pthread_exit() directly at all, just return from compute(), the pthreads library will then call pthread_exit() for you, passing it whatever void* value you choose to return.
your accept loop should not be calling pthread_join() at all. It blocks the calling thread until the specified thread terminates. That defeats the whole purpose of using threads to handle your clients, and prevents your server from accepting more than 1 client at a time. If you are going to use pthread_join() at all, it should be after the accept loop has ended, so you can wait for any worker threads that may still be running before exiting the app. But that also means keeping track of the pthread_t values that pthread_create() returns, which is more work.
With that said, try this code instead:
Client code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h>
#define FILE_ADDR "/dev/urandom"
char* readMsg(int sockfd, size_t *msgSize)
{
*msgSize = 0;
unsigned int length = 0;
int bytes_read = read(sockfd, &length, sizeof(length)); //Receive number of bytes
if (bytes_read <= 0) {
perror("Error in receiving message from server\n");
return NULL;
}
length = ntohl(length);
char *buffer = malloc(length+1);
if (!buffer) {
perror("Error in allocating memory to receive message from server\n");
return NULL;
}
char *pbuf = buffer;
unsigned int buflen = length;
while (buflen > 0) {
bytes_read = read(sockfd, pbuf, buflen); // Receive bytes
if (bytes_read <= 0) {
perror("Error in receiving message from server\n");
free(buffer);
return NULL;
}
pbuf += bytes_read;
buflen -= bytes_read;
}
*msgSize = length;
return buffer;
}
int sendMsg(int sockfd, char *msg, size_t msgSize)
{
unsigned int convertedNum = htonl(msgSize);
if (write(sockfd, &convertedNum, sizeof(convertedNum)) < 0) { //Send number of bytes
perror("error writing to socket");
return -1;
}
if (write(sockfd, msg, msgSize) < 0) { //Send bytes
perror("error writing to socket");
return -1;
}
return 0;
}
int main(int argc, char *argv[]) {
char* ptr;
//Get command line arguments
unsigned int port = atoi(argv[2]);
unsigned int length = strtoul(argv[3], &ptr, 10); //Number of bytes to read
char* buffer = malloc(length); //Buffer to hold data read from file
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in serv_addr;
int sockfd = -1;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo);
if (rv != 0) {
perror("getaddrinfo error\n");
return 1;
}
for (p = servinfo; p != NULL; p = p->ai_next) {
//Initialize socket
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd < 0)
continue;
//Initialize connection
rv = connect(sockfd, p->ai_addr, (socklen_t) p->ai_addrlen);
if (rv == 0)
break;
close(sockfd);
sockfd = -1;
}
freeaddrinfo(servinfo);
if (sockfd == -1) {
perror("socket create/connect error\n");
return 1;
}
size_t msgSize;
char *msg = readMsg(sockfd, &msgSize);
if (!msg) {
close(sockfd);
return 1;
}
printf("%.*s\n", (int)msgSize, msg);
free(msg);
//Open file for reading
FILE *fp = fopen(FILE_ADDR, "rb");
if (fp == NULL) {
perror("Error in file open\n");
close(sockfd);
return 1;
}
printf("file opened\n");
if (fread(buffer, 1, length, fp) != length) {
perror("Error reading from file\n");
fclose(fp);
close(sockfd);
return 1;
}
fclose(fp);
printf("Buffer is %.*s\n", (int)length, buffer);
if (sendMsg(sockfd, buffer, length) != 0) {
free(buffer);
close(sockfd);
return 1;
}
free(buffer);
printf("send is done \n");
msg = readMsg(sockfd, &msgSize); // response from server
if (!msg) {
close(sockfd);
return 1;
}
printf("# of printable characters: %.*s\n", (int)msgSize, msg);
free(msg);
return 0;
}
Server code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h>
#include <pthread.h>
#include <signal.h>
static volatile int keepRunning = 1;
int pcc_total[159];
void intHandler(int dummy) {
keepRunning = 0;
}
char* readMsg(int sockfd, size_t *msgSize)
{
*msgSize = 0;
unsigned int length = 0;
int bytes_read = read(sockfd, &length, sizeof(length)); //Receive number of bytes
if (bytes_read <= 0) {
perror("Error in receiving message from server\n");
return NULL;
}
length = ntohl(length);
char *buffer = malloc(length+1);
if (!buffer) {
perror("Error in allocating memory to receive message from server\n");
return NULL;
}
char *pbuf = buffer;
unsigned int buflen = length;
while (buflen > 0) {
bytes_read = read(sockfd, pbuf, buflen); // Receive bytes
if (bytes_read <= 0) {
perror("Error in receiving message from server\n");
free(buffer);
return NULL;
}
pbuf += bytes_read;
buflen -= bytes_read;
}
*msgSize = length;
return buffer;
}
int sendMsg(int sockfd, char *msg, size_t msgSize)
{
unsigned int convertedNum = htonl(msgSize);
if (write(sockfd, &convertedNum, sizeof(convertedNum)) < 0) { //Send number of bytes
perror("error writing to socket");
return -1;
}
if (write(sockfd, msg, msgSize) < 0) { //Send bytes
perror("error writing to socket");
return -1;
}
return 0;
}
void *compute(void *socket_desc) {
int sock = * (int*) socket_desc;
free(socket_desc);
if (sendMsg(sock, "hi", 2) != 0) {
perror("error writing to socket\n");
close(sock);
return NULL;
}
size_t length = 0;
char *data = readMsg(sock, &length);
if (!msg) {
close(sock);
return NULL;
}
printf("len is %d\n", (int)length);
printf("data is %.*s\n", (int)length, data);
int count = 0;
for (size_t i = 0; i < length; i++) {
// ...
}
free(data);
char scount[20];
sprintf(scount, "%d", count);
sendMsg(sock, scount, strlen(scount));
close(sock);
return NULL;
}
int main(int argc, char *argv[]) {
unsigned int port = atoi(argv[1]);
signal(SIGINT, intHandler);
int socket_desc, client_sock, c, *new_sock;
struct sockaddr_in server, client;
socket_desc = socket( AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1) {
perror("Could not create server socket");
return 1;
}
printf("server socket created\n");
memset(&server, 0, c);
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(port);
if (bind(socket_desc, (struct sockaddr*) &server, sizeof(server)) < 0) {
perror("\n Error : Bind Failed \n");
close(socket_desc);
return 1;
}
printf("bind created\n");
if (listen(socket_desc, 10) < 0) {
perror("\n Error : Listen Failed \n");
close(socket_desc);
return 1;
}
printf("listening\n");
while (keepRunning) {
c = sizeof(client);
client_sock = accept(socket_desc, (struct sockaddr *) &client,
(socklen_t*) &c);
if (client_sock < 0) {
perror("\n Error : Accept Failed\n");
continue;
}
printf("client accepted\n");
new_sock = malloc(sizeof(int));
if (!new_sock) {
perror("\n Error : Malloc Failed\n");
close(client_sock);
continue;
}
*new_sock = client_sock;
pthread_t tid;
if (pthread_create(&tid, NULL, &compute, new_sock) != 0) {
perror("\n Error : Thread Create Failed\n");
free(new_sock);
close(client_sock);
continue;
}
printf("thread created\n");
}
close(socket_desc);
return 0;
}
I think you should remove the two lines
close(client_sock);
free(new_sock);
in the server code because the newly created thread can't perform on those variables and memory area if it is freed up at such an early point. Can you try the code again without it?
Your server closes the connected socket and frees the memory in which you stored its file handle immediately after launching the thread to handle that connection. You're unlucky that the server only hangs as a result, but you have data races, so formally your program's behavior is undefined.
Since the server isn't going to do anything else until the thread has finished, you might as well move the close() and free() after the pthread_join(). Or, considering that you do join before creating any other threads, how about just calling compute() synchronously instead of creating a new thread for it to run in?
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.
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.