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.
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've just started taking network programming classes and this is what we did in class in order to make connection between client and server. My problem is that I cannot connect to the server, it just stops after printing "addrinfo is successful" and does not loop through.
We used 8080 for port number in class and that did not work, so I tried using 7070 and it worked maybe 1 out of 50 times. I don't have any problems with the client side of the program, it works completely fine. I'm using Visual Studio Code on MacBook if that makes any difference, I also tried using the terminal but that did not work either.
//client to server
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
int main(){
const char *hostname = "127.0.0.1";
const char *portNumber = "7070";
int clientSocket; //socketFD
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
struct addrinfo *results; // const for head
struct addrinfo *record; // temp for traversing
int error;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(hostname, portNumber, &hints, &results);
// error checking
if(error >= 0){
printf("Client: getaddressinfo() successful\n ");
}
//traversing the list
for(record = results; record != NULL; record = record->ai_next){
clientSocket = socket(record->ai_family, record->ai_socktype, 0);
if(clientSocket == -1){
continue;
}
if(connect(clientSocket, record->ai_addr, record-> ai_addrlen) != -1){
break;
}
close(clientSocket);
}
//socket() and connect() both were success
//send()
if(record == NULL){
printf("Error\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(results);
printf("socket status: created and connected\n");
char *message = "Hello" ;
if(send(clientSocket, message, strlen(message), 0) == -1){
printf("Error\n");
exit(EXIT_FAILURE);
}
else{
printf("Message sent successfuly\n");
}
close(clientSocket);
return 0;
}
//server
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
int main(){
printf("Starting the server\n");
const size_t bufferSize = 1024;
const char *portNumber = "7070";
const int backlog = 1;
int serverSocket;
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo *results;
struct addrinfo *record;
if((getaddrinfo(NULL, portNumber, &hints, &results)) != 0){
printf("Error\n");
exit(EXIT_FAILURE);
}
printf("addrinfo is successful\n");
//traverse through the list
for(record = results; record != NULL; record = record->ai_next){
serverSocket = socket(record->ai_family, record->ai_socktype, record->ai_protocol);
if(serverSocket == -1){
continue;
}
int enable = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
if(bind(serverSocket, record->ai_addr, record->ai_addrlen) == 0){
break;
}
close(serverSocket);
}
if(record == NULL){
exit(EXIT_FAILURE);
}
freeaddrinfo(results);
printf("Socket status: created and binded successfuly\n");
if(listen(serverSocket, backlog) == -1){
printf("ERROR\n");
exit(EXIT_FAILURE);
}
printf("Server is listening\n");
while(1){
int clientSocket;
struct sockaddr clientAddress;
socklen_t clientAddressLength = sizeof(clientAddress);
if((clientSocket = accept(serverSocket, &clientAddress, &clientAddressLength)) <0){
printf("Error\n");
exit(EXIT_FAILURE);
}
printf("Client socket accepted\n");
char buffer[bufferSize];
if(recv(clientSocket, buffer, sizeof(buffer), 0) == -1){
printf("Error\n");
exit(EXIT_FAILURE);
}
printf("Message is received: %s\n", buffer);
close(clientSocket);
printf("Client socket is closed\n");
}
return 0;
}
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?
I have a server that acknowledges a command and then sends data. It works fine with the command line: echo "show version" | nc -q1 127.0.0.1 5000 gives:
Command received: show version
Beta
I have a client that should behave exactly the same as the command line test, but it hangs on the second read() call unless I run it on a different server. I've had the same issue with unix domain sockets, except that they occasionally work.
Why would it fail only on localhost?
Client Source
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define ERR_FAIL_CONNECT -1
#define ERR_SOCK_SELECT -2
#define ERR_SOCK_READ -3
#define ERR_SOCK_WRITE -3
#define ERR_SOCK_REMOTE_CLOSED -4
int tcpConnect (char *ipAddr, int port);
int sendCommand (char *buf, int bufSize);
int readWithTimeout (int sock, char *buf, int bufSize, struct timeval *timeout);
int main() {
char buf[64];
int nBytes;
strcpy(buf, "show version");
nBytes = sendCommand(buf, sizeof(buf));
printf("Response: %s\n", buf);
return 0;
}
int sendCommand (char *buf, int bufSize) {
int apiSock;
int nBytes = ERR_SOCK_SELECT;
int len;
struct timeval timeout;
apiSock = tcpConnect("127.0.0.1", 5000);
if (!apiSock) return ERR_FAIL_CONNECT;
len = strlen(buf);
nBytes = write(apiSock, buf, len);
if (nBytes < 0) {
perror("ERROR writing to socket");
nBytes = ERR_SOCK_WRITE;
}
else if (nBytes < len) {
fprintf(stderr, "Command truncated at %d/%d\n", nBytes, len);
nBytes = ERR_SOCK_WRITE;
}
else {
timeout.tv_sec = 3;
timeout.tv_usec = 0;
nBytes = readWithTimeout(apiSock, buf, bufSize, &timeout);
if (nBytes > 0) {
timeout.tv_sec = 20;
timeout.tv_usec = 0;
nBytes = readWithTimeout(apiSock, buf, bufSize, &timeout);
}
}
close(apiSock);
return nBytes;
}
int tcpConnect (char *ipAddr, int port) {
struct sockaddr_in addr;
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("ERROR: Could not create TCP socket");
return 0;
}
addr.sin_addr.s_addr = inet_addr(ipAddr);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("ERROR: Could not connect");
return 0;
}
return sock;
}
int readWithTimeout (int sock, char *buf, int bufSize, struct timeval *timeout) {
int res;
int nBytes = ERR_SOCK_SELECT;
fd_set set;
fprintf(stderr, "readWithTimeout(sock=%d, buf='%s', bufSize=%d, timeout{tv_sec=%d, tv_usec=%d})\n",
sock, buf, bufSize, timeout->tv_sec, timeout->tv_usec);
FD_ZERO(&set);
FD_SET(sock, &set);
res = select(sock+1, &set, NULL, NULL, timeout);
if (res < 0) perror("ERROR waiting for data");
else if (res == 0) fprintf(stderr, "Timed out waiting for data\n");
else {
nBytes = read(sock, buf, bufSize);
if (nBytes < 0) {
perror("ERROR reading from socket");
nBytes = ERR_SOCK_READ;
}
else if (nBytes == 0) {
fprintf(stderr, "Remote end closed socket\n");
shutdown(sock, 2);
close(sock);
nBytes = ERR_SOCK_REMOTE_CLOSED;
}
}
return nBytes;
}
Server Source
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define TCP_PORT 5000
#define BUF_SIZE 512
int readCommand(int clientSockFd);
void myWrite (int fileDescriptor, const void *buf, size_t nbytes);
int main (void) {
socklen_t client_len;
int optval;
int flags;
struct sockaddr_in serv_addr, client_addr;
int serverSockFd;
int clientSockFd;
fd_set set;
struct timeval timeout;
int rv;
serverSockFd = socket(AF_INET, SOCK_STREAM, 0);
if(serverSockFd < 0) perror("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(TCP_PORT);
if(bind(serverSockFd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("Unable to bind TCP socket");
}
listen(serverSockFd, 5);
client_len = sizeof(client_addr);
flags = fcntl(serverSockFd, F_GETFL, 0);
if (flags < 0) perror("Unable to read TCP socket flags");
flags = flags|O_NONBLOCK;
fcntl(serverSockFd, F_SETFL, flags);
// Wait for client connections
while(1) {
clientSockFd = accept(serverSockFd, (struct sockaddr *) &client_addr, &client_len);
if(clientSockFd < 0) {
usleep(50000);
continue;
}
//After connected, inner loop to read and write multiple packages
while(1) {
FD_ZERO(&set);
FD_SET(clientSockFd, &set);
timeout.tv_sec = 15;
timeout.tv_usec = 0;
rv = select(clientSockFd+1, &set, NULL, NULL, &timeout);
if(rv == -1) {
perror("select");
continue;
}
else if(rv == 0) {
printf("TCP timeout, closing client connection.\n");
shutdown(clientSockFd, 2);
break;
}
if (!readCommand(clientSockFd)) break;
}
close(clientSockFd);
}
close(serverSockFd);
return 0;
}
int readCommand(int sock) {
int nBytes;
int len;
char inBuf[BUF_SIZE];
char outBuf[BUF_SIZE];
nBytes = read(sock, inBuf, BUF_SIZE);
if(nBytes < 0) perror("ERROR reading from TCP socket");
else if(nBytes == 0) {
printf("Client closed TCP socket\n");
shutdown(sock, 2);
return nBytes;
}
else {
// Acknowledge command
len = sprintf(outBuf, "Command received: %s", inBuf);
if (write(sock, outBuf, len+1) < 0) {
perror("ERROR writing to TCP socket");
}
// Send response data
if (!strncmp("show version", inBuf, 12)) strcpy(outBuf, "Beta");
else strcpy(outBuf, "Invalid command");
if (write(sock, outBuf, strnlen(outBuf, BUF_SIZE-1)+1) < 0) {
perror("ERROR writing to TCP socket");
}
}
return nBytes;
}
I just realized both the acknowledgement and the data were consumed in the first read() when running the client on localhost.
So I need to parse the result of the first read before attempting a second.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm trying to send data from a server to a client whenever the client executes a recv() command. As the code stands right now, I cannot get the client to print any data it receives. I cannot figure out whether something is wrong with my server or client, so any help would be appreciated. Thanks!
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#define ECHO_PORT 9999
#define BUF_SIZE 4096
int main(int argc, char* argv[])
{
if (argc != 3)
{
fprintf(stderr, "usage: %s <server-ip> <port>",argv[0]);
return EXIT_FAILURE;
}
char buf[BUF_SIZE];
int status, sock, sock2;
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
struct addrinfo *servinfo; //will point to the results
hints.ai_family = AF_INET; //IPv4
hints.ai_socktype = SOCK_STREAM; //TCP stream sockets
hints.ai_flags = AI_PASSIVE; //fill in my IP for me
if ((status = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo error: %s \n", gai_strerror(status));
return EXIT_FAILURE;
}
if ((sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1)
{
fprintf(stderr, "Socket failed");
return EXIT_FAILURE;
}
if ((connect(sock, (struct sockaddr *) servinfo->ai_addr, servinfo->ai_addrlen)) != 0)
{
fprintf(stderr, "Connection failed");
return EXIT_FAILURE;
}
if ((sock2 = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1)
{
fprintf(stderr, "Socket failed");
return EXIT_FAILURE;
}
if ((connect(sock2, (struct sockaddr *) servinfo->ai_addr, servinfo->ai_addrlen)) != 0)
{
fprintf(stderr, "Connection failed");
return EXIT_FAILURE;
}
while (1) {
//char msg[BUF_SIZE] = "ashudfshuhafhu";
//char msg[BUF_SIZE];
//fgets(msg, BUF_SIZE, stdin);
//int i = 2;
//if (strlen(msg) == i)
// break;
int bytes_received;
// fprintf(stdout, "Sending %s", msg);
//send(sock, msg , strlen(msg), 0);
if((bytes_received = recv(sock, buf, BUF_SIZE, 0)) > 1)
{
buf[bytes_received] = '\0';
fprintf(stdout, "Received %s", buf);
}
}
freeaddrinfo(servinfo);
close(sock);
return EXIT_SUCCESS;
}
Server.c
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define ECHO_PORT 9999
#define BUF_SIZE 4096
int close_socket(int sock)
{
if (close(sock))
{
fprintf(stderr, "Failed closing socket.\n");
return 1;
}
return 0;
}
int main(int argc, char* argv[])
{
int sock, client_sock;
ssize_t readret;
socklen_t cli_size;
struct timeval tv;
struct sockaddr_in addr, cli_addr;
char buf[BUF_SIZE] = "wetwetwetwetwetwetwetwet";
fd_set readfds, writefds;
fd_set activereadfds, activewritefds;
cli_size = sizeof(&cli_addr);
tv.tv_sec = 5;
tv.tv_usec = 0;
fprintf(stdout, "----- Echo Server -----\n");
/* all networked programs must create a socket */
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "Failed creating socket.\n");
return EXIT_FAILURE;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(ECHO_PORT);
addr.sin_addr.s_addr = INADDR_ANY;
/* servers bind sockets to ports---notify the OS they accept connections */
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)))
{
close_socket(sock);
fprintf(stderr, "Failed binding socket.\n");
return EXIT_FAILURE;
}
if (listen(sock, 5))
{
close_socket(sock);
fprintf(stderr, "Error listening on socket.\n");
return EXIT_FAILURE;
}
FD_ZERO(&readfds);
FD_SET(sock, &activereadfds);
while (1)
{
fprintf(stdout,"in here.\n");
readfds = activereadfds;
writefds = activewritefds;
FD_ZERO(&activereadfds);
FD_ZERO(&activewritefds);
if (select(51, &readfds, &writefds, NULL, &tv) < 0)
{
perror("select");
return EXIT_FAILURE;
}
for (int i = 0; i < 10; ++i)
{
if (FD_ISSET (i, &readfds))
{
if (i == sock)
{
fprintf(stdout, "main loop. \n");
client_sock = accept(sock,
(struct sockaddr *) &cli_addr, &cli_size);
FD_SET(client_sock, &activereadfds);
FD_SET(client_sock, &activewritefds);
if (client_sock < 0)
{
perror("accept");
return EXIT_FAILURE;
}
} else {
fprintf(stdout, "second loop \n");
readret = send(i,buf, strlen(buf),0);
if (readret < 0)
fprintf(stdout, "yay");
}
}
if (FD_ISSET(i, &writefds))
{ fprintf(stdout, "ugh \n");
readret = send(i,buf,BUF_SIZE,0);
//if (readret > 0)
//while((readret = recv(i, buf, BUF_SIZE, 0)) >= 1)
// {
//if (send(i, buf, readret, 0) != readret)
//{
// close_socket(i);
// close_socket(sock);
// fprintf(stderr, "Error sending to client.\n");
// return EXIT_FAILURE;
//}
}
}
}
close_socket(sock);
return EXIT_SUCCESS;
}
Your server is sending only when the socket is ready for reading, and as the client is never sending, the server isn't either. The server send should happen when the client socket turns up in the writefds, although actually this isn't the correct way to use that feature. Really you should just send, and only add into and worry about writefds if send() caused EAGAIN/EWOULDBLOCK.
You could be getting an undetected error in the client:
if((bytes_received = recv(sock, buf, BUF_SIZE, 0)) > 1)
{
buf[bytes_received] = '\0';
fprintf(stdout, "Received %s", buf);
}
This should continue:
else if (bytes_received == 0)
{
fprintf(stdout, "peer disconnected\n");
break;
}
else // < 0: error
{
fprintf(stdout, "recv() error %s\n", strerror(errno));
break;
}
You need to print the actual error like this whenever you get an error from a system call.