Hello i made this code to open a socket and make a thread to send data so the socket
int is_valid_fd(int fd)
{
return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}
int main(int Count, char *Strings[])
{
pfd.events = POLLIN;
pfd.revents = 0;
/*---Create streaming socket---*/
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("Socket");
exit(errno);
}
/*---Initialize address/port structure---*/
bzero(&self, sizeof(self));
self.sin_family = AF_INET;
self.sin_port = htons(MY_PORT);
self.sin_addr.s_addr = INADDR_ANY;
/*---Assign a port number to the socket---*/
if ( bind(sockfd, (struct sockaddr*)&self, sizeof(self)) != 0 )
{
perror("socket--bind");
exit(errno);
}
/*---Make it a "listening socket"---*/
if ( listen(sockfd, 20) != 0 )
{
perror("socket--listen");
exit(errno);
}
err = pthread_create(&(tid), NULL, &thread_accept, NULL);
if (err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
/*---Forever... ---*/
while(1){
if(0<poll(&pfd,1,100)){
if(pfd.revents & POLLIN){
run = read(pfd.fd, &t,1);
}
}
if(run){
if(is_valid_fd(clientfd))send(clientfd, "12 ",3,0);
/*---Close data connection---*/
}
printf("hejsa\n");
fflush(stdout);
sleep(1);
}
/*---Clean up (should never get here!)---*/
close(sockfd);
return 0;
}
void* thread_accept(){
while (1){
/*---accept a connection (creating a data pipe)---*/
clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen);
pfd.fd=clientfd;
printf("%s:%d, connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
run=1;
/*---Echo back anything sent---*/
send(clientfd, buffer, recv(clientfd, buffer, MAXBUF, 0), 0);
//close(clientfd);
}
}
My problem is then, that when i close the socket connection, the program shuts down instead of just closing the socket and keep printf("hejsa\n)
I don't see where you break the while loop?
you should also protect your shared data with mutex or something.
I have a short example that do something similar(but in different way) here
Related
I'm trying to implement an application using select(), but without closing the socket already served and without removing the corrispondent file descriptor from the main set of monitored socket (at least not immediatly). The goal is to create something similar to a set of "persistent connections".
The problem is that after I checked the ready socket, recv() continue to receive the last message a peer sent (running the code below, "Received" is printed infinited times). My thought is that the socket is still "ready", but I can't "mark" it as "unready" or "unchecked" to check it again only if there's a new message from that peer, and close it only in determinate conditions. How can I mark that socket as unready without close it? Is there another solution to implement persistent connections with select()?
Here it is a code of a simple application that I'm trying to program to understand how to realize persistent connections.
Server:
int main () {
int ret, sd, new_sd, len, i;
char buffer[1024];
fd_set master;
fd_set read_fds;
int fdmax;
struct sockaddr_in my_addr;
FD_ZERO(&master);
FD_ZERO(&read_fds);
sd = socket(AF_INET, SOCK_STREAM, 0);
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(4257);
my_addr.sin_addr.s_addr = INADDR_ANY;
ret = bind(sd, (struct sockaddr*)&my_addr, sizeof(my_addr));
if(ret<0) {
perror("Error: ");
exit(1);
}
ret = listen(sd,10);
if(ret<0) {
perror("Error: ");
exit(-1);
}
FD_SET(sd, &master);
fdmax = sd;
for(;;) {
read_fds = master;
select(fdmax+1, &read_fds, NULL, NULL, NULL);
for(i=0; i<=fdmax; i++) {
if(FD_ISSET(i, &read_fds)) {
if(i == sd) {
len = sizeof(cl_addr);
new_sd = accept(sd, (struct sockaddr*)&cl_addr, &len);
FD_SET(new_sd, &master);
if(new_sd > fdmax)
fdmax = new_sd;
}
else {
ret = recv(i, buffer, 4, 0);
printf("Error: %s\n", strerror(errno));
printf("Received.\n");
if(strcmp(buffer, "DEL")==0) { /*Connection is closed only if client request it*/
close(i);
FD_CLR(i, &master);
printf("%d closed.\n",i);
continue;
}
len=strlen(buffer);
ret = send(i, (void*)buffer, len, 0);
if(ret<0) {
printf("socket n%d :\n",i);
perror("Error \n");
}
}
}
}
}
close(sd);
return 0;
}
I would be really grateful if you would help me, it is very important to me.
Edit: Client side is correct and send only once. "printf("Error: %s\n", strerror(errno));" print always "Success". After the first correct receiving, the program print infinite times these two printf after recv and buffer is empty.
Client:
int main (int argc, char* argv[]) {
int ret, sd, i, len;
char buffer[1024];
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[1]));
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
for(;;) {
scanf("%s",buffer);
if(strcmp(buffer,"c")==0) {
sd = socket(AF_INET, SOCK_STREAM, 0);
ret = connect(sd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if(ret<0) {
perror("Error ");
exit(1);
}
}
if(strcmp(buffer, "REQ\0")==0) {
ret = send(sd, buffer, sizeof(buffer), 0);
if(ret<0) {
perror("Error ");
exit(1);
}
ret = recv(sd, (void*)buffer, 7, 0);
if(ret<0) {
perror("Error ");
exit(1);
}
printf("Received: %s\n", buffer);
}
if(strcmp(buffer, "DEL\0")==0) {
ret = send(sd, buffer, sizeof(buffer), 0);
if(ret<0) {
perror("Error ");
exit(1);
}
close(sd);
return 0;
}
}
}
I have created a server and client communication system in C and when the server is shutdown or quit, the client goes into an infinite loop repeating the last received message instead of quitting. I think the problem lies in recieveMessage function declaration but can't seem to pinpoint it.
How do I resolve this and how can I avoid this in the future?
#include"stdio.h"
#include"stdlib.h"
#include"sys/types.h"
#include"sys/socket.h"
#include"string.h"
#include"netinet/in.h"
#include"netdb.h"
#include"pthread.h"
#define PORT 4444
#define BUF_SIZE 2000
void * receiveMessage(void * socket) {
int sockfd, ret;
char buffer[BUF_SIZE];
sockfd = (int) socket;
memset(buffer, 0, BUF_SIZE);
for (;;) {
ret = recvfrom(sockfd, buffer, BUF_SIZE, 0, NULL, NULL);
if (ret < 0) {
printf("Error receiving data!\n");
break;
} else {
printf("server: ");
fputs(buffer, stdout);
//printf("\n");
}
}
}
int main(int argc, char**argv) {
struct sockaddr_in addr, cl_addr;
int sockfd, ret;
char buffer[BUF_SIZE];
char * serverAddr;
pthread_t rThread;
if (argc > 2) {
printf("usage: client < ip address >\n");
exit(1);
}
serverAddr = argv[1];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
printf("Error creating socket!\n");
exit(1);
}
printf("Socket created...\n");
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.31.90");
addr.sin_port = PORT;
ret = connect(sockfd, (struct sockaddr *) &addr, sizeof(addr));
if (ret < 0) {
printf("Error connecting to the server!\n");
exit(1);
}
printf("Connected to the server...\n");
memset(buffer, 0, BUF_SIZE);
printf("Enter your messages one by one and press return key!\n");
//creating a new thread for receiving messages from the server
ret = pthread_create(&rThread, NULL, receiveMessage, (void *) sockfd);
if (ret) {
printf("ERROR: Return Code from pthread_create() is %d\n", ret);
exit(1);
}
while (fgets(buffer, BUF_SIZE, stdin) != NULL) {
ret = sendto(sockfd, buffer, BUF_SIZE, 0, (struct sockaddr *) &addr, sizeof(addr));
if (ret < 0) {
printf("Error sending data!\n\t-%s", buffer);
break;
}
puts(buffer);
}
close(sockfd);
pthread_exit(NULL);
return 0;
}
recvfrom returns zero when the other end of the connection is closed, not < 0.
Change your test of the return result as follows:
if (ret == 0)
{
printf("Connection closed!\n");
exit(0);
}
else if (ret < 0) {
printf("Error connecting to the server!\n");
exit(1);
}
I've set up a very simple C socket server, there are two files.
main.c:
#include "socket_server.h"
#include "main.h"
int main (int argc, char* argv[])
{
start_socket_server(SOCKET_SERVER_PORT);
while (1)
{
update_clients();
}
return 0;
}
socket_server.c:
#include "socket_server.h"
int listen_fd, fdmax, newfd, nbytes, i, j, k;
char buf[256];
fd_set master;
fd_set read_fds;
struct timeval tv;
void start_socket_server(int port)
{
struct sockaddr_in servaddr;
FD_ZERO(&master);
FD_ZERO(&read_fds);
bzero( &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(port);
tv.tv_sec = 0;
tv.tv_usec = 100;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(listen_fd, 10);
FD_SET(listen_fd, &master);
fdmax = listen_fd;
}
void update_clients()
{
read_fds = master;
select(fdmax+1, &read_fds, NULL, NULL, &tv);
for(i = 0; i<= fdmax; i++)
{
if (FD_ISSET(i, &read_fds))
{
if (i == listen_fd) //new connection
{
newfd = accept(listen_fd, (struct sockaddr *) NULL, NULL);
if (newfd != -1)
{
fprintf(stderr, "New connection!");
FD_SET(newfd, &master);
if (newfd > fdmax) {
fdmax = newfd;
}
}
} else {
nbytes = recv(i, buf, sizeof buf, 0);
if(nbytes <= 0)
{
fprintf(stderr, "Dead");
close(i);
FD_CLR(i, &master);
} else {
for(j = 0; j <= fdmax; j++)
{
if(FD_ISSET(j, &master))
{
if(j != listen_fd && j != i)
{
fprintf(stderr, "%s", buf);
}
}
}
}
}
}
}
}
Then I have a simple flash file to connect to it with the following actionscript:
var socket = new XMLSocket;
socket.connect("12.34.56.78", 8080);
socket.onConnect = function(status) {
if(status) {
trace("connected");
socket.writeUTF("Hello!");
socket.flush();
} else {
trace("couldn't connect");
}
};
If I run the server, then my actionscript, I would expect the following:
Server sits and waits
Flash file starts
Server says "New connection!" and flash file says "connected"
Server says "Hello!".
Only 1-3 happen. "Hello!" is never output to my terminal. In fact as best I can tell this block:
nbytes = recv(i, buf, sizeof buf, 0);
if(nbytes <= 0)
{
fprintf(stderr, "Dead");
close(i);
FD_CLR(i, &master);
} else {
for(j = 0; j <= fdmax; j++)
{
if(FD_ISSET(j, &master))
{
if(j != listen_fd && j != i)
{
fprintf(stderr, "%s", buf);
}
}
}
}
Is never executed at all (except for when I close my flash file and the server prints "Dead".
What's going on? Why can't I see the data sent from flash? I've managed to send data TO flash, but I haven't been able to receive any FROM it. Also this is being run from within flash, so there is no need to worry about policy files at this stage.
You need to set all your sockets to be non-blocking. For example,
void start_socket_server(int port)
{
struct sockaddr_in servaddr;
int val;
FD_ZERO(&master);
FD_ZERO(&read_fds);
bzero( &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(port);
tv.tv_sec = 0;
tv.tv_usec = 100;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == ioctl(listen_fd, FIONBIO, (val = 1, &val)))
{
perror("ioctl failed!\n");
goto ERROR; /* TODO: or however else you want to deal with errors */
}
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(listen_fd, 10);
FD_SET(listen_fd, &master);
fdmax = listen_fd;
}
...
if (i == listen_fd) //new connection
{
newfd = accept(listen_fd, (struct sockaddr *) NULL, NULL);
if (newfd != -1)
{
int val;
fprintf(stderr, "New connection!");
if (-1 == ioctl(newfd, FIONBIO, (val = 1, &val)))
{
perror("ioctl failed!\n");
goto ERROR; /* TODO: or however else you want to deal with errors */
}
FD_SET(newfd, &master);
if (newfd > fdmax) {
fdmax = newfd;
}
}
} else {
nbytes = recv(i, buf, sizeof buf, 0);
if(nbytes <= 0)
{
fprintf(stderr, "Dead");
close(i);
FD_CLR(i, &master);
} else {
fprintf(stdout, "Received %d bytes: '%s'\n", nbytes, buf);
}
}
You should also do this on your main listening socket too after you create it initially so that you can't get stuck in a call to accept() somehow.
Also, the way you are outputting read-in data doesn't make much sense. As initially posted, the code would only print out if it had multiple client connections established. Then, when data was read in, it would print it N - 1 times, where N was the number of current client connections.
I keep getting a "Accept: too many files" error after running my server.c code. Trying to get it to create new threads for clients and limit connections with semaphores.
This is my code:
#define MAX_CLIENTS 30
sem_t s;
void *handle(void *pnewsock);
int sockfd, new_fd, numbytes; // listen on sock_fd, new connection on new_fd
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
socklen_t sin_size;
pthread_t thread;
int main(void){
//initialise locks
sem_init(&s, 0, 0);
/* generate the socket */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(true);
}
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP
/* bind the socket to the end point */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) {
perror("bind");
exit(true);
}
/* start listnening */
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(true);
}
printf("server starts listening ...\n");
/* Main loop */
while (1) {
sin_size = sizeof(struct sockaddr_in);
if (pthread_create(&thread, NULL, handle, &new_fd) != 0) {
fprintf(stderr, "Failed to create thread\n");
}
}
return 0;
}
void *handle(void *pnewsock){
int value;
sem_getvalue(&s,&value);
while (value >= MAX_CLIENTS){
printf("too many connections");
sem_wait(&s);
}
if (value < MAX_CLIENTS){
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
&sin_size)) == -1) {
perror("accept");
exit(1);
}
printf("server: got connection from %s\n", \
inet_ntoa(their_addr.sin_addr));
char buffer[MAXDATASIZE];
char res[MAXDATASIZE];
memset(buffer, '\0', MAXDATASIZE);
memset(res, '\0', sizeof(res));
if ((numbytes=recv(new_fd, buffer, sizeof(buffer), 0)) == -1) {
perror("recv");
exit(true);
}
else if(numbytes == 0) {
printf("client left");
sem_post(&s);
close(new_fd);
exit(false);
}
else {
buffer[numbytes] = '\0'; // add null terminator
printf("Request: %s\n",buffer);
//search function
}
}
close(new_fd);
exit(false);
return NULL;
}
Can anyone give me some insight to this file leak? Thanks
The main() function is creating pthreads using an infinite loop. Your error is very likely related to this since the loop will keep on creating newer threads.
/* Main loop */
while (1) {
sin_size = sizeof(struct sockaddr_in);
if (pthread_create(&thread, NULL, handle, &new_fd) != 0) {
fprintf(stderr, "Failed to create thread\n");
}
}
What you probably meant was to create one thread for each client. And if that is the case, then the handle() function should call pthread_create() whenever it gets a new client from the accept() call. The server (the socket for which we call listen and accept) does not need multiple threads -- one thread -- which can be the main thread -- is all it needs.
The following code is a test program wriiten to understand the behaviour of select() call in a TCP client program.
What I observe is that the select is not blocking, instead the program is blocking on recv().
The output is as follows:
Wait on select.
Wait on recv.
...
My question is why the select() returns a success? Ideally it should be blocking on the select() instead of recv().
The TCP server is sending a character string of 15 bytes once in 3 seconds.
int clientfd = -1;
int dummyfd = -1;
int maxfd = -1;
struct sockaddr_in server_addr;
char recv_buf[100] = {0};
int msg_len = 0;
int bytes_recv = 0;
fd_set readfd;
int retval = 0;
/* Open the socket and a dummy socket */.
clientfd = socket(AF_INET, SOCK_STREAM, 0);
dummyfd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == clientfd || -1 == dummyfd)
{
perror("socket error: ");
exit(1);
}
printf("Socket opened : %d\n", clientfd);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(10000);
//server_addr.sin_addr.s_addr = INADDR_ANY;
inet_aton("127.0.0.1", &(server_addr.sin_addr));
memset(&(server_addr.sin_zero), 0, 8);
/* Connect to server */
if(connect(clientfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)))
{
perror("connect error: ");
exit(1);
}
printf("Connect Success\n");
maxfd = (clientfd > dummyfd) ? (clientfd + 1) : (dummyfd + 1);
while(1)
{
FD_ZERO(&readfd);
FD_SET(clientfd, &readfd);
FD_SET(dummyfd, &readfd);
printf("Wait on select\n");
retval = select(maxfd , &readfd, NULL, NULL, NULL);
if(retval <= 0)
{
printf("select failed\n");
}
else
{
printf("Wait on recv\n");
/* ... The process waits here ... */
bytes_recv = recv(clientfd, recv_buf, 100, 0);
printf("%d: Bytes recv = %d\t%s\n", retval, bytes_recv, recv_buf);
memset(recv_buf, 0 ,100);
}
}
close(clientfd);
return 0;
}
Edit: Without dummyfd, the program works as intended.
A follow up question:
When the server is closed abruptly, how to detect this using select()?
Can the program be modified so that is blocks on select() when the server side, say, crashes?
Use the following to be sure it's the clientfd that's returning from the select:
else if (FD_ISSET(clientfd, &readfd)) {
Don't have time to test, but I suspect the dummyfd is returning as an EOF from the select, not the clientfd.
After select() returns, you will want to conditionally receive from clientfd. My guess is that there may be data on dummyfd that is triggering the select to complete, but the receive is on the clientfd.
retval = select(maxfd , &readfd, NULL, NULL, NULL);
if(retval <= 0)
{
printf("select failed\n");
}
else
{
if (FD_ISSET(clientfd, &readfd))
{
bytes_recv = recv(clientfd, recv_buf, 100, 0);
...
}
if (FD_ISSET(dummyfd, &readfd))
{
/* "dummyfd" processing */
}