TCP server can not accept client connect beyond 1000? - c

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.

Related

Why a TCP socket server written in C should not close client file descriptors in worker pthreads, but can close them in forked worker processes?

I wrote a simple TCP socket server in C, which creates a new child worker thread when it accepts a new connection request from a client and simply counts and sends numbers. If a client terminates, the corresponding child worker thread should also terminate, while the other threads should not.
If all clients are written in Python, when a client terminates, "Connection is reset by peer" is printed on the server, but everything else is fine, that is, other threads and clients are still working.
But if a client is written in C, when any clients and their corresponding child worker threads terminate, other threads also terminate, which is not expected. Why does it happen? I rewrote the server in Python, but this did not happen no matter what language the client is written in.
I then commented out close(*client_fd); and the issue is solved. I haven't got a clue, since it works fine in the server using fork().
The C code for server using pthread is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#define PORT 9000
#define CONNECTIONS 2
#define MAX_BUFFER_SIZE 1024
struct sockaddr_in socket_address;
socklen_t socket_address_size = sizeof(socket_address);
int server_fd;
void *handle_request(void *fd) {
int *client_fd = (int *) fd;
char buffer[MAX_BUFFER_SIZE] = {0};
for (int i = INT_MAX; send(*client_fd, buffer, strlen(buffer), 0) >= 0 && i >= 0; i--) {
printf("%d\r\n", i);
sprintf(buffer, "%d", i);
}
if (close(*client_fd) < 0) {
perror("close client_fd");
}
return NULL;
}
int main(int argc, char *argv[]) {
int option = 1;
char buffer[MAX_BUFFER_SIZE] = {0};
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket");
exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &option, sizeof(option))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
socket_address.sin_family = AF_INET;
socket_address.sin_addr.s_addr = htonl(INADDR_ANY);
socket_address.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr *) &socket_address, socket_address_size) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
if (listen(server_fd, CONNECTIONS) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
pthread_t threads[CONNECTIONS];
int client_fds[CONNECTIONS];
for (int i = 0; i < CONNECTIONS; i++) {
client_fds[i] = accept(server_fd, (struct sockaddr *) &socket_address, &socket_address_size);
if (client_fds[i] < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
if (pthread_create(&threads[i], NULL, handle_request, &client_fds[i]) < 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
}
for (int i = 0; i < CONNECTIONS; i++) {
if (pthread_join(threads[i], NULL) < 0) {
perror("pthread_join");
}
}
close(server_fd);
return EXIT_SUCCESS;
}
The C code for server using fork() is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#define PORT 9000
#define CONNECTIONS 2
#define MAX_BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
struct sockaddr_in socket_address;
socklen_t socket_address_size = sizeof(socket_address);
int server_fd, client_fd, option = 1;
char buffer[MAX_BUFFER_SIZE] = {0};
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket");
exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &option, sizeof(option))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
socket_address.sin_family = AF_INET;
socket_address.sin_addr.s_addr = htonl(INADDR_ANY);
socket_address.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr *) &socket_address, socket_address_size) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
if (listen(server_fd, CONNECTIONS) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
pid_t pids[CONNECTIONS];
for (int i = 0; i < CONNECTIONS; i++) {
pids[i] = fork();
if (pids[i] < 0) {
perror("fork");
exit(EXIT_FAILURE);
} else if (pids[i] == 0) {
if ((client_fd = accept(server_fd, (struct sockaddr *) &socket_address, &socket_address_size)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
for (int i = INT_MAX; send(client_fd, buffer, strlen(buffer), 0) >= 0 && i >= 0; i--) {
printf("%d\r\n", i);
sprintf(buffer, "%d", i);
}
close(client_fd);
return EXIT_SUCCESS;
}
}
for (int i = 0; i < CONNECTIONS; i++) {
int wstatus;
if (waitpid(0, &wstatus, WUNTRACED) < 0) {
perror("waitpid");
}
}
close(server_fd);
return EXIT_SUCCESS;
}
The C code for client is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define IP_ADDRESS "127.0.0.1"
#define PORT 9000
#define MAX_BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
int socket_fd;
struct sockaddr_in socket_address;
socklen_t socket_address_size = sizeof(socket_address);
ssize_t message_len;
char buffer[MAX_BUFFER_SIZE] = {0};
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket");
exit(EXIT_FAILURE);
}
socket_address.sin_family = AF_INET;
socket_address.sin_addr.s_addr = inet_addr(IP_ADDRESS);
socket_address.sin_port = htons(PORT);
if (connect(socket_fd, (struct sockaddr *) &socket_address, socket_address_size) < 0) {
perror("connect");
exit(EXIT_FAILURE);
}
while ((message_len = recv(socket_fd, buffer, MAX_BUFFER_SIZE, 0)) > 0) {
buffer[message_len] = '\0';
puts(buffer);
}
close(socket_fd);
return EXIT_SUCCESS;
}
The Python code for server is as follows:
import socket
import threading
HOST = ''
PORT = 9000
CONNECTIONS = 2
TRUNK_SIZE = 1024
def handle_request(connection):
with connection:
count = 0
while True:
state = connection.send(f'{count}\r\n'.encode('utf-8'))
if not state:
print(f"Connection closed from {address}.")
break
print(count)
count += 1
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR | socket.SO_REUSEPORT, 1)
s.bind((HOST, PORT))
s.listen(CONNECTIONS)
threads = []
for c in range(CONNECTIONS):
connection, address = s.accept()
print(f'Connected by {address}.')
thread = threading.Thread(target=handle_request, args=(connection,), daemon=True)
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
The Python code for client is as follows:
import socket
HOST = '127.0.0.1'
PORT = 9000
TRUNK_SIZE = 1024
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
while True:
data = s.recv(TRUNK_SIZE).decode('utf-8')
if not data:
print("Connection closed.")
break
print(data)
If your whole process suddenly goes down while writing to a socket, then due to a SIGPIPE signal you received (indicated by the error EPIPE). The standard action of SIGPIPE is to terminate the process. Implement a signal handler which will catch SIGPIPE signals (and probably ignore or deal with it).
The message "Connection is reset by peer" is an indication of a caught SIGPIPE signal.

Creation of sockets from scratch using TCP_REPAIR?

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?

In TCP socket program,client send some data, but server need read multiple times. why?

I have a question about socket.I send N-size data from client to server, N-size less than 100 byte.So I think my data should not be split to multiple tcp packet.In my opinion, Client send data should be done at one times and Server can receive data at one time.But The result is not satisfactory.Real situation is the server need call read data.I don't understand it.Follow code:
epoll_server.cpp(only receive data.)
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <netdb.h>
#define BUFSIZE 1024
#define INITSIZE 1024
#define MAXEVENTCOUNT 10240
// add non-blocking to sockfd
int make_socket_non_blocking(int fd)
{
// get initial flag
int src_flags;
src_flags= fcntl(fd, F_GETFL,0);
if(src_flags == -1)
{
perror("fcntl get error.");
return-1;
}
// add non-blocking
int new_flags = src_flags | O_NONBLOCK;
int ret_value;
ret_value = fcntl(fd, F_SETFL, new_flags);
if(ret_value == -1)
{
perror("fcntl set error.");
return-1;
}
return 0;
}
// main function
int main(int argc, char* argv[])
{
int server_sockfd, client_sockfd;
int server_len;
struct sockaddr_in server_address;
// create server socket fd
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
// init server address struct
bzero(&server_address, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(9567);
server_address.sin_addr.s_addr = INADDR_ANY;
server_len = sizeof(server_address);
// bind server address info for server fd
if((bind(server_sockfd, (struct sockaddr*)&server_address, server_len)) == -1)
{
perror("bind error");
exit(EXIT_FAILURE);
}
// let server is listened state
listen(server_sockfd, 5);
printf("server start waiting for connect...\r\n");
// only suggestion
int efd = epoll_create(INITSIZE);
if(-1 == efd)
{
printf("epoll_create error happen.\n");
return -1;
}
// set server_sockfd
struct epoll_event server_event, event;
server_event.data.fd = server_sockfd;
server_event.events = EPOLLIN | EPOLLET;
int ret_epollctl = epoll_ctl(efd, EPOLL_CTL_ADD, server_sockfd, &server_event);
if(-1 == ret_epollctl)
{
printf("epoll_ctl error happen when efd is adding server_sockfd.\n");
return -1;
}
/* event loop */
struct epoll_event* return_events;
// set timeout is 3000 ms
int timeout_msecond = 3000;
return_events = (struct epoll_event*)malloc(MAXEVENTCOUNT*sizeof(struct epoll_event));
int count = 0;
while(1)
{
int ret_epollwait = epoll_wait(efd, return_events, MAXEVENTCOUNT, timeout_msecond);
// part_1:epoll_wait error happen
if(-1 == ret_epollwait)
{
printf("logged epoll_wait error happen.\n");
continue;
}
// part_2:epoll_wait timeout
if(0 == ret_epollwait)
{
printf("logged epoll_wait timeout.\n");
continue;
}
// part_3:do some other event
int index = 0;
for(index = 0; index < MAXEVENTCOUNT; index++)
{
// part_3-1:hup ...
if((return_events[index].events & EPOLLERR)
|| (return_events[index].events & EPOLLHUP)
|| !(return_events[index].events & EPOLLIN) )
{
continue;
}
// part_3-2:is connection
if(return_events[index].data.fd == server_sockfd)
{
struct sockaddr_in client_address;
int client_len = sizeof(client_address);
// server accept connection from client
int client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_address, (socklen_t*)&client_len);
// part_3-2-1:connection error happen
if(-1 == client_sockfd)
{
if((EAGAIN == errno)
|| (EWOULDBLOCK == errno) )
{
continue;
}
else
{
printf("accept error occured.\n");
continue;
}
}
else // part_3-2-2:normal connection
{
// get clinet some information
char hostinfo_buf[BUFSIZE] = {0};
char servname_buf[BUFSIZE] = {0};
int tmp_ret = getnameinfo((struct sockaddr*)&client_address, client_len, hostinfo_buf, sizeof(hostinfo_buf), servname_buf, sizeof(servname_buf), NI_NUMERICHOST| NI_NUMERICSERV);
if(0 == tmp_ret)
{
printf("Accepted connection on descriptor %d:ip=%s, port=%s.\n", client_sockfd, hostinfo_buf, servname_buf);
}
// set client_sockfd to non-blocking
tmp_ret = make_socket_non_blocking(client_sockfd);
if(-1 == tmp_ret)
{
printf("set client_sockfd=%d to non-blocking error occured.\n", client_sockfd);
abort();
}
// set client_sockfd is EPOLLIN, EPOLLET
event.data.fd = client_sockfd;
event.events = EPOLLIN | EPOLLET;
tmp_ret = epoll_ctl(efd, EPOLL_CTL_ADD, client_sockfd, &event);
if(tmp_ret == -1)
{
printf("efd add %d has a error.\n", client_sockfd);
continue;
}
printf("add descriptor %d:ip=%s, port=%s successfully.\n", client_sockfd, hostinfo_buf, servname_buf);
}
continue;
}
// part_3-3:read data from client
printf("read data start++++\n");
int temp = 0;
// get recv_cache size start
int recvsize = 0;
socklen_t optlen = sizeof(recvsize);
int err = getsockopt(return_events[index].data.fd, SOL_SOCKET, SO_RCVBUF, &recvsize, &optlen);
printf("recv cache size :%d\n", recvsize);
// get recv_cache size end
while(1) // start while(1)
{
printf("%d times read data\n", ++temp);
char* recv_buffer = (char*)malloc(1024+1);
memset(recv_buffer, 0, 1025);
// int ret_read = read(return_events[index].data.fd, recv_buffer, sizeof(recv_buffer));
int ret_read = recv(return_events[index].data.fd, recv_buffer, sizeof(recv_buffer), 0);
// part_3-3-1:read return error
if(-1 == ret_read)
{
if(EAGAIN != errno)
{
printf("read data from %d error occured, errno=%d, %s.\n", return_events[index].data.fd, errno, strerror(errno));
}
break;
}
// part_3-3-2:no data
if(0 == ret_read)
{
continue;
}
// part_3-3-3:output data. If data is 'bye', connection will close.
if(ret_read > 0)
{
printf("%d client's data:size=%dbyte, content=%s\n", return_events[index].data.fd, ret_read, recv_buffer);
// part_3-3-3-1:close connection and remove client_sockfd
if((recv_buffer[0] == 'b')
&& (recv_buffer[1] == 'y')
&& (recv_buffer[2] == 'e') )
{
close(return_events[index].data.fd);
printf("close %d, ", return_events[index].data.fd);
int tmp_ret = epoll_ctl(efd, EPOLL_CTL_DEL, return_events[index].data.fd, NULL);
if(tmp_ret == -1)
{
printf("efd del %d has a error.\n", client_sockfd);
}
printf("remove descriptor %d successfully.\n", return_events[index].data.fd);
}
}
} // end of while(1)
printf("read data finish------\n");
}
}
free(return_events);
// close server_sockfd
shutdown(server_sockfd, 2);
return 0;
}
epoll_client.cpp(only send data.)
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#define BUFSIZE 1024
int main(int argc, char* argv[])
{
int sock_clientfd, ret_recvsize, i;
struct sockaddr_in dest, mine;
char send_buffer[BUFSIZE + 1];
// create socket fd
if ((sock_clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Socket");
exit(EXIT_FAILURE);
}
// init server address that client will connetct to.
bzero(&dest, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(9567);
if(argc != 2)
{
printf("Usage: %s <dest ip>\n", argv[0]);
printf("Usage: %s 127.0.0.1\n", argv[0]);
return -1;
}
printf("-----\n");
if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)
{
perror(argv[1]);
exit(1);
}
// connect to server
printf("will connect!\n");
if (connect(sock_clientfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
{
perror("Connect ");
exit(EXIT_FAILURE);
}
while(1)
{
bzero(send_buffer, BUFSIZE + 1);
printf("input message:");
fgets(send_buffer, BUFSIZE, stdin);
send_buffer[strlen(send_buffer) - 1] = '\0';
printf("%d\n", strlen(send_buffer));
int send_retsize = send(sock_clientfd, send_buffer, strlen(send_buffer), 0);
if(send_retsize == -1)
{
perror("send data to client error happen!");
exit(EXIT_FAILURE);
}
printf("send succ data:%s\n", send_buffer);
if((send_buffer[0] == 'b')
&& (send_buffer[1] == 'y')
&& (send_buffer[2] == 'e') )
{
printf("client active close connect.\n");
break;
}
}
// close sock_clientfd
close(sock_clientfd);
return 0;
}
Follow pircture is some run info:
epoll_server.png
epoll_client.png
The server read data is only 8 byte, Is the kernel design epoll is this?
I guess the reasons are as follows pirture:
The reason you don't receive everything that is available in one read is because you only read 8 bytes at a time.
char* recv_buffer = (char*)malloc(1024+1);
int ret_read = recv(return_events[index].data.fd, recv_buffer, sizeof(recv_buffer), 0);
// part_3-3-1:read return error
recv_buffer is a char* not an array, so sizeof recv_buffer equals the size of a pointer which in your case is 8.
Note that you should never rely on data arriving in packages. If your message protocol states that you should be getting 10 bytes never expect all 10 bytes to be available at once. You should always code in a way that can handle data being split up into multiple reads.
If the thread handles a single socket then a simple do { read... } while (total_bytes_received < expected_bytes); will suffice.
If the thread handles multiple connections, then you need to save the bytes you have read and then continue to manage other sockets that are ready before returning to your handling loop that will use select/epoll to wait for more data.

TCP server/client how to keep connections alive?

I wrote a simple TCP echo server to handle multiple clients. It uses select() to get multiple connections.
Server Code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
int create_listener(uint16_t port) {
int listen_fd;
struct sockaddr_in name;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) {
perror ("socket");
exit(EXIT_FAILURE);
}
bzero(&name, sizeof(name));
name.sin_family = AF_INET;
name.sin_addr.s_addr = htonl(INADDR_ANY);
name.sin_port = htons(port);
if (bind(listen_fd, (struct sockaddr *) &name, sizeof(name)) < 0) {
perror ("bind");
exit(EXIT_FAILURE);
}
return listen_fd;
}
int read_from_client(int fd) {
char buffer[100];
int nbytes;
nbytes = read(fd, buffer, 100);
if (nbytes < 0) {
perror("read");
exit(EXIT_FAILURE);
}
else if (nbytes == 0) {
return -1;
}
else {
fprintf(stderr, "Server: got message: %s\n", buffer);
write(fd, buffer, strlen(buffer) + 1);
return 0;
}
}
int main(int argc, char *argv[]) {
int listen_fd;
uint16_t port = 22000;
fd_set active_fd_set, read_fd_set;
int i;
struct sockaddr_in servaddr;
/* Create the socket and set it up to accept connections. */
listen_fd = create_listener(port);
if (listen(listen_fd, 10) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
/* Initialize the set of active sockets. */
FD_ZERO(&active_fd_set);
FD_SET(listen_fd, &active_fd_set);
while (1) {
/* Block until input arrives on one or more active sockets. */
read_fd_set = active_fd_set;
if (select(FD_SETSIZE, &read_fd_set, NULL, NULL, 0) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
/* Service all the sockets with input pending. */
for (i = 0; i < FD_SETSIZE; ++i) {
if (FD_ISSET(i, &read_fd_set)) {
if (i == listen_fd) {
/* Connection request on original socket. */
int new_fd;
new_fd = accept(listen_fd, (struct sockaddr *) NULL, NULL);
if (new_fd < 0) {
perror ("accept");
exit(EXIT_FAILURE);
}
FD_SET(new_fd, &active_fd_set);
}
else {
/* Data arriving on an already-connected socket. */
if (read_from_client(i) < 0) {
close(i);
FD_CLR(i, &active_fd_set);
}
}
}
}
}
return 0;
}
Client code:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int sockfd, n;
char sendline[100];
char recvline[100];
struct sockaddr_in servaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(22000);
inet_pton(AF_INET, "127.0.0.1", &(servaddr.sin_addr));
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
while (1) {
bzero(sendline, 100);
bzero(recvline, 100);
fgets(sendline, 100, stdin);
write(sockfd, sendline, strlen(sendline) + 1);
read(sockfd, recvline, 100);
printf("%s", recvline);
}
return 0;
}
The problem is when I run server in one terminal and run two clients in another two terminals. If I use Ctrl+C to terminate one client, the server automatically terminates. I'm wondering why the server acts this way. What I'm expecting is the server runs forever. When client 1 terminates, server should still has a live connection with client 2.
Looks like you're hitting the exit in read_from_client. In general, in a server that serves multiple clients, you probably don't want to exit when you have a failure with one of the client connections.

C - simple encrypting socket with tcp connections fail to encrypt big files

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.

Resources