Related
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(){
struct sockaddr_in svraddr;
int clisock;
pid_t pid;
ssize_t nlen;
struct sockaddr_in cliaddr;
socklen_t cliaddrlen = sizeof(sockaddr_in);
char buf[BUFSIZ];
svraddr.sin_family=AF_INET;
svraddr.sin_port=htons(49510);
svraddr.sin_addr.s_addr=htonl(INADDR_ANY);
int serversock = socket(PF_INET,SOCK_STREAM,0);
if(serversock==-1){
perror("socket()");
exit(1);
}
if(bind(serversock,(struct sockaddr*)&svraddr,sizeof(svraddr))==-1){
perror("bind()");exit(1);
}
if(listen(serversock,10)==-1){
perror("listen()");exit(1);
}
while(1){
clisock = accept(serversock,(struct sockaddr*)&cliaddr,&cliaddrlen);
switch(pid=fork()){
case -1:
perror("fork()");exit(1);
case 0:
close(serversock);
printf("CONN: client %s:%d\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));
while((nlen=read(clisock,buf,BUFSIZ))!=0){
perror("read");
printf("RECV: srcport %d, %s\n",ntohs(cliaddr.sin_port),buf);
write(clisock,"received successfully",22);
}
close(clisock);
printf("DISCONN: client %d disconnected\n",ntohs(cliaddr.sin_port));
exit(0);
break;
default:
close(clisock);
}
}
}
Above is the entire codes for server.
It is simple multiprocess based server.
what I understood is : accept() should give client address into cliaddr.
it does, but it doesn't for the first one.
but strangely, Socket I/O works well.
the code is written from scratch. What did I do wrong with this?
I tried initializing cliaddr with memset, no luck.
output for server is:
CONN: client 0.0.0.0:0
DISCONN: client 0 disconnected
CONN: client 127.0.0.1:57078
DISCONN: client 57078 disconnected
accept() should always gives correct client address anytime.
Never mind. I've figure out why.
socklen_t cliaddrlen = sizeof(sockaddr_in);
=>
socklen_t cliaddrlen = sizeof(struct sockaddr_in);
I don't understand why this code's been successfully compiled.
but yes, my mistake. now it works like charm.
I'm working on a simple client/server implementation in which the client connects to the server based on the command line argument that specifies the hostname to search for a socket to connect with on (I just input localhost) and then sends a singular string that is reversed by the server, and then this reversed string is sent back to the client, and the reversed string prints. I am able to connect to the socket that lives at localhost (the client) but writing through the socket fails, and I am not sure why.
This is the server code: It has a built in reverser function that manually reverses a string and then writes it back through the socket to the client after reading in the original message that was written to the server by the client
#include <netdb.h>
#define BACKLOG 20
#include "server.h"
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_MESSAGE_LENGTH 200
char* reverse(char * word){
char *reversed;
int m=strlen(word);
reversed=(char*)(malloc(sizeof(char) * m));
printf("%d",m);
int i=0;
while (i++!=m){
char d= *(word+m-i);
strncat(reversed,&d,1);
}
return reversed;
}
void reverser_response(int sockfd,char *write_buff,char *read_buff){
read(sockfd,read_buff,sizeof(read_buff));
char *reversed_message=reverse(read_buff);
int i=0;
while (*(reversed_message)!='\0'){
write_buff[i]=*(reversed_message);
i++;
reversed_message=reversed_message+i;
}
write(sockfd,write_buff,sizeof(write_buff));
bzero(write_buff,sizeof(write_buff));
bzero(read_buff,sizeof(read_buff));
}
int main(){
int cfd,afd;
//I'm pretty sure service will be the port name
char service[NI_MAXSERV];
//hostname will be the name of the IP address
char host[NI_MAXHOST];
char read_buff[200];
char write_buff[200];
//I rmemember hints is used to set certain settings within the struct addrinfo result we create
struct addrinfo hints;
//this is used for looping through possible addrinfo structus
struct addrinfo *result, *rp;
//I think this stores the address of the client that connect with us
struct sockaddr_storage claddr;
//combined host + service name with padding of 10 bits
char addrstr[NI_MAXHOST+NI_MAXSERV+10];
memset(&hints,0,sizeof(struct addrinfo));
//socklen is the size of the socket
socklen_t socklen;
//I think AF_UNSPEC means that we can use an unspecified IP protocl: IPV4 or IPV6
hints.ai_family=AF_UNSPEC;
//stream socket
hints.ai_socktype=SOCK_STREAM;
hints.ai_next=NULL;
hints.ai_canonname=NULL;
hints.ai_addr=NULL;
//Passive: we wait for someone to join with our socket, numeric serv: use the numeric host name
hints.ai_flags=AI_PASSIVE | AI_NUMERICSERV;
//getadrrinfo: 0 is success, takes in as arguments, NULL(?) our port number, references to the hints and result addrinfo structs
//actually getaddrinfo generates a linked list of addrinfo structs for the specified host name/service name
//in this case, result is the head of the linkedlist, hints is the hints thing that sets csome conditions
if ((getaddrinfo(NULL,PORT_NUM,&hints,&result))!=0){
printf("Failed to get result pointer of address structs");
exit(EXIT_FAILURE);
}
//loop through possible addrinfo structs we can successfully create a socket at. Create socket at every possible struct. If we are successful
//in binding then quit. bind takes as arguments the socket's file descriptor, the address of the socket, and the lenth of the socket's address
//socket takes as arguments the addrinfo structu's ai_family (IPV4/6), socketpye (stream socket), and the protocol?
for (rp=result;rp;rp!=NULL){
cfd=socket(rp->ai_family,rp->ai_socktype, rp->ai_protocol);
if (cfd==-1){
continue;
}
//rp->ai_addr could be a pointer to a sockaddr_in or sockaddr_in6
if (bind(cfd,rp->ai_addr, rp->ai_addrlen)==0){
break;
}
}
if (rp==NULL){
printf("Reached end of address list without finding suitable socket address space");
exit(EXIT_FAILURE);
}
freeaddrinfo(result);
if (listen(cfd,BACKLOG)==0){
printf("Server listening....\n");
}
for (;;){
socklen=sizeof(struct sockaddr);
afd=accept(cfd,(struct sockaddr*) &claddr,&socklen);
if (afd==-1){
perror("Accept failed");
}
getnameinfo((struct sockaddr*) &claddr,socklen,
host,NI_MAXHOST,service,NI_MAXSERV,0);
snprintf(addrstr,NI_MAXSERV+NI_MAXHOST+10, "Connection received from: (%s, %s)", host,service);
printf("%s\n",addrstr);
reverser_response(afd,write_buff,read_buff);
}
close(afd);
close(cfd);
}
And this is the server implementation, which sends a message to the server, and then reads through the socket the reversed message the server sends back:
#include <netdb.h>
#include "server.h"
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "struct.h"
#define MAX_MESSAGE_LENGTH 200
void chat_function(int sockfd,char *write_buffer,char *read_buffer){
printf("\nEnter a message to send to the server. The server will reverse it, and send it back\n");
fscanf(stdin,"%s",write_buffer);
int m=strlen(write_buffer);
write_buffer[m]='\0';
int i=0;
if (write(sockfd,write_buffer,sizeof(write_buffer))!=0){
printf("Failed to send message to server\n");
exit(EXIT_FAILURE);
}
read(sockfd,read_buffer,sizeof(read_buffer));
int j=strlen(read_buffer);
read_buffer[j]='\0';
int z=0;
printf("Reversed server response:\n");
while (read_buffer[z]!='\0'){
printf("%c",read_buffer[z]);
z++;
}
}
int main(int argc, char*argv[]){
struct addrinfo hints;
struct addrinfo *result, *rp;
int cfd;
socklen_t socklen;
memset(&hints,0,sizeof(struct addrinfo));
hints.ai_family=AF_UNSPEC; //can accept IPV4 or IPV6
hints.ai_socktype=SOCK_STREAM;
hints.ai_next=NULL;
hints.ai_canonname=NULL;
hints.ai_addr=NULL;
hints.ai_flags=AI_NUMERICSERV;
char addbuff[NI_MAXSERV+NI_MAXHOST+10];
char write_buffer[MAX_MESSAGE_LENGTH];
char read_buffer[MAX_MESSAGE_LENGTH];
bzero(write_buffer,sizeof(write_buffer));
bzero(read_buffer,sizeof(read_buffer));
if (argc<2){
printf("Failed to give hostname for client");
exit(EXIT_FAILURE);
}
if ((getaddrinfo(argv[1],PORT_NUM,&hints,&result))!=0){
printf("You did not provide a legitimate host name for the client socket to search through addresses to connect to");
exit(EXIT_FAILURE);
}
for (rp=result;rp;rp=rp->ai_next){
cfd=socket(rp->ai_family,rp->ai_socktype, rp->ai_protocol);
if (cfd==-1){
continue;
}
if (connect(cfd,rp->ai_addr,rp->ai_addrlen)!=-1){
int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (cfd, SOL_SOCKET, SO_ERROR, &error, &len);
if (retval==0){
printf("Socket successfully connected\n");
}
break;
}
}
chat_function(cfd,write_buffer,read_buffer);
if (rp==NULL){
printf("Could not connect socket to any address");
exit(EXIT_FAILURE);
}
close(cfd);
}
With the server running as a background process, I attempt to write to the server like so:
./client localhost (this connects the client to the socket that lives at localhost, the server)
and when I actually execute the client, I get back the error message I have in my code indicating the write through the socket in the client failed. Furthermore, when adding a print statement to the server's reversal method that outputs the length of the string it received as an arugment to reverse, it will be able to identify the string length of the string it received. This further confuses me - if my client is failing to even write through the socket, how is the server able to know the length of the word it's supposed to reverse?
try with send() and recv() instead of write() and read()
and the next problem is these functions most of the time fail when you want to get more than four byte so you need to do something like this:
(you shouldn't send or take all of them at once.
// allocate 4 byte memory for Memory2Send
Remained_Data = i;
j = 0
while (Remained_Data > 0){
if(Remained_Data > 4){
memcpy(Memory2Send, Memory4Data + j, 4;
send(Sock, Memory2Send, 4, 0);
j = j + 4;
Remained_Data = Remained_Data - 4;
}
else if(Remained_Data < 4){
memcpy(Memory2Send, Memory4Data + j, 4;
send(Sock, Memory2Send, Remained_Data, 0);
Remained_Data = 0;
}
try to send 4 bytes every round. you'll get all the data
and for server-side you need to receive 4 bytes every round.
// allocate 4 byte memory for Memory4Recv
j = 1;
z = 0;
while (j != 0) {
bzero(Memory4Recv,4);
recv(Sock, Memory4Recv, 4, 0);
for (i = 0; i < 4; i++){
Recv_Data[z] = Memory4Recv[i];
if (Recv_Data[z] == 0x00){
j = 0;
break;
}
z++;
}
}
put a null byte at the end of the reserved memory and if the size is equal to i send, i + 1;
if you want to communicate better, send more than 4 bytes each round and get a more reliable connection, you should do it on kernel-side. but first, get better in C and user-side socket programming then go for kernel-side.
I am trying to learn the basic of network communication using sockets in C. My client program takes in a message from the user, echoes it server side and back, and prints out the received message. When I fire both of them up for the first time, they both work exactly as expected. However, if I quit the client side and then fire it up again while keeping the server program running, my echoed messages become off by one.
I assumed it was because the last message is getting caught in the pipe or something, and after poking around, I saw that someone suggested to use shutdown() to flush out the pipe, but that doesn't seem to be working. I also tried to zero out the buffers wherever I thought they may be lingering, but that didn't seem to help, either.
server.c
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#define PORT 12403
#define BUFFER_MAX 1024
#define BACKLOG_MAX 1024
int clientSocket;
int serverSocket;
void listening()
{
while (1)
{
struct sockaddr_in clientAddress;
socklen_t addressLength = sizeof(clientAddress);
/*---accept a connection (creating a data pipe)---*/
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &addressLength);
if (clientSocket > -1)
{
printf("%s:%d connected\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
break;
}
}
}
int main(int Count, char *Strings[])
{
struct sockaddr_in socketInfo;
char buffer[BUFFER_MAX];
//Create socket
if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Setting the linger option to off and resuse address option to on for testing
int option = 0;
setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, &option, sizeof(option));
option = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
//Initialize socket information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(PORT);
socketInfo.sin_addr.s_addr = INADDR_ANY;
//Assign a port number to the socket
if (bind(serverSocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error binding socket");
exit(errno);
}
//Set socket to listen
if (listen(serverSocket, BACKLOG_MAX) != 0)
{
perror("Error setting socket to listen");
exit(errno);
}
listening();
//Once first socket has been connected, begin echoing process
int i = 0;
while (1)
{
//Clear the buffer
bzero(buffer, BUFFER_MAX);
//Echo back anything sent
//Close connection and begin listening process again if the client disconnects
int sendCheck;
int readCheck;
readCheck = recv(clientSocket, buffer, BUFFER_MAX, 0);
if (readCheck <= 0)
{
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
sleep(1);
listening();
}
sendCheck = send(clientSocket, buffer, BUFFER_MAX, 0);
if (sendCheck <= 0)
{
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
sleep(1);
listening();
}
i++;
}
close(serverSocket);
return 0;
}
client.c
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <stdlib.h>
#include <resolv.h>
#include <netdb.h>
#define PORT 12403
#define LOCALHOST "127.0.0.1"
#define BUFFER_MAX 1024
int socketStatus = 0;
void sigpipeHandler()
{
perror("Connection to server terminated\n");
socketStatus = 0;
}
int main()
{
int mySocket;
struct sockaddr_in socketInfo;
char buffer[BUFFER_MAX];
int count = 0;
//Create socket
if ((mySocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Get IP address of required host machine
char* hostName = "<host name removed>";
int portNumber = PORT;
char* ipAddr = NULL;
struct hostent* host = NULL;
host = gethostbyname(hostName);
ipAddr = inet_ntoa(*((struct in_addr*) host->h_addr_list[0]));
//Initialize server information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(portNumber);
if (inet_aton(ipAddr, (struct in_addr *)&socketInfo.sin_addr.s_addr) == 0)
{
perror("Error assigning IP address");
exit(errno);
}
//Set up sigpipe handler
signal(SIGPIPE, sigpipeHandler);
//Connect to server
if (connect(mySocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error connecting");
exit(errno);
}
//Indicate that socket is OK
socketStatus = 1;
while(1)
{
if(!socketStatus) {shutdown(mySocket, SHUT_WR); break;}
printf("Please enter a command.\n");
char command[BUFFER_MAX];
bzero(command, BUFFER_MAX);
fgets(command, sizeof(command), stdin);
send(mySocket, command, BUFFER_MAX, 0);
//Get echoed message
bzero(buffer, BUFFER_MAX);
recv(mySocket, buffer, sizeof(buffer), 0);
printf("Echo [%d]:%s\n", ++count, buffer);
}
//Close socket
close(mySocket);
return 0;
}
I did some cleanup on your server code and this seems to work.
For my testing, the client code is unchanged. But, as others have suggested, you should check the error codes from send and recv. Also, note that if you ctrl-c the server, the client will hang in the fgets, so it won't detect the server abort until you hit return after the prompt. Not a big deal, but I thought I'd mention it.
I also added a fork so you can have multiple clients talking to the same server instance simultaneously.
I tested this with two clients [in two xterm windows] talking with the single server instance.
I moved your echo code into a new function docomm. A small difference from your code is that any error from either recv or send breaks out of the loop and closes the connection. All connections from new clients are guaranteed to start with a recv call.
In your code, you would not always break out of the loop, but close the connection and call listening again. This would happen for either send or recv. If it happened on the wrong one, this might be the source of the problem you were having because you could do a send before a recv to a new client initially.
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>
#define PORT 12403
#define BUFFER_MAX 1024
#define BACKLOG_MAX 1024
int clientSocket;
int serverSocket;
int forkflg = 1;
void listening()
{
while (1)
{
struct sockaddr_in clientAddress;
socklen_t addressLength = sizeof(clientAddress);
/*---accept a connection (creating a data pipe)---*/
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &addressLength);
if (clientSocket > -1)
{
printf("%s:%d connected\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
break;
}
}
}
void
docomm(void)
{
char buffer[BUFFER_MAX];
//Once first socket has been connected, begin echoing process
int i = 0;
while (1) {
//Clear the buffer
bzero(buffer, BUFFER_MAX);
//Echo back anything sent
//Close connection and begin listening process again if the client disconnects
int sendCheck;
int readCheck;
readCheck = recv(clientSocket, buffer, BUFFER_MAX, 0);
if (readCheck <= 0)
break;
sendCheck = send(clientSocket, buffer, BUFFER_MAX, 0);
if (sendCheck <= 0)
break;
i++;
}
printf("close\n");
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
}
int main(int Count, char *Strings[])
{
struct sockaddr_in socketInfo;
//Create socket
if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Setting the linger option to off and resuse address option to on for testing
int option = 0;
setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, &option, sizeof(option));
option = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
//Initialize socket information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(PORT);
socketInfo.sin_addr.s_addr = INADDR_ANY;
//Assign a port number to the socket
if (bind(serverSocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error binding socket");
exit(errno);
}
//Set socket to listen
if (listen(serverSocket, BACKLOG_MAX) != 0)
{
perror("Error setting socket to listen");
exit(errno);
}
while (1) {
listening();
if (! forkflg) {
docomm();
continue;
}
pid_t pid = fork();
if (pid == 0) {
docomm();
exit(0);
}
while (waitpid(0,NULL,WNOHANG) > 0);
}
close(serverSocket);
return 0;
}
UPDATE:
Just from a glance: 1) Can I ask why you created a fork flag if you never change the value of it? Should it be changed somewhere?
I used forkflg so you can set it to zero (e.g. int forkflg = 0;) to run sequentially. Or, you could add some code and parse argv looking for an option (e.g. -f) to set/clear it [for testing/debug purposes]. For production code, you'd want forkflg to be set and could remove the flag and just do the fork case always [adjusting the code to match].
Just tracing through the program mentally, it seems like the forking section will never be executed. Correct me where I'm wrong: after initially setting the socket to listen, the while loop will enter, and listening() will be called. Execution will halt in listening() until a connection is accepted.
Yes, that's true.
Control will return to main, where docomm() gets called. Control stays in docomm() until the connection breaks, at which point it returns to main and continue gets called, skipping the fork stuff and starting the process over again. So does the fork stuff ever get executed?
What you're describing is the behavior if forkflg is zero.
The fork is called if forkflg is set. Note that, in that case, docomm is called in the child and not the parent (because fork returned 0). So, the parent will not be blocked while the child does the echoing.
Thus, the parent returns immediately and is free to do the waitpid loop to reap any old children and restart the main/outer loop.
The waitpid loop only happens when a new connection comes in, so several children may have already terminated and will stay in zombie state until the waitpid loop gets executed [which will reap any/multiple pending children].
A cleaner way to reap the children might be to set up a signal handler for SIGCHLD and have it do the waitpid loop. This would reap all spent children immediately, without having to wait for a new connection to roll in.
Or, with the signal handler, add the waitpid loop to listening [inside the current loop] because if a SIGCHLD signal comes in, accept will return immediately with errno set to EINTR
I created a TCP client and a server in C and executed it in two terminals. But after changing and compiling the code, I could not get the output. Both server and client keep running and print nothing.
Here is my server code
/* Sample TCP server */
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
int fsize(FILE *fp){
int prev=ftell(fp);
fseek(fp, 0L, SEEK_END);
int sz=ftell(fp);
fseek(fp,prev,SEEK_SET); //go back to where we were
return sz;
}
int main(int argc, char**argv)
{
int listenfd,connfd,n, length;
struct sockaddr_in servaddr,cliaddr;
socklen_t clilen;
char* banner = "ack";
char buffer[1000];
/* one socket is dedicated to listening */
listenfd=socket(AF_INET,SOCK_STREAM,0);
/* initialize a sockaddr_in struct with our own address information for binding the socket */
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(32000);
/* binding */
bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
listen(listenfd,0);
clilen=sizeof(cliaddr);
while(1){
/* accept the client with a different socket. */
connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
// the uninitialized cliaddr variable is filled in with the
n = recvfrom(connfd,buffer,1000,0,(struct sockaddr *)&cliaddr,&clilen);//information of the client by recvfrom function
buffer[n] = 0;
sendto(connfd,banner,strlen(banner),0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
printf("Received:%s\n",buffer);
FILE *fp = fopen("serverfile.txt", "r");
length = fsize(fp);
printf("%d\n", length);
}
return 0;
}
Here is my client code
/* Sample TCP client */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char**argv)
{
int sockfd,n;
struct sockaddr_in servaddr;
char banner[] = "Hello TCP server! This is TCP client";
char buffer[1000];
if (argc != 2)
{
printf("usage: ./%s <IP address>\n",argv[0]);
return -1;
}
/* socket to connect */s
sockfd=socket(AF_INET,SOCK_STREAM,0);
/* IP address information of the server to connect to */
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=inet_addr(argv[1]);
servaddr.sin_port=htons(32000);
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
sendto(sockfd,banner,strlen(banner),0, (struct sockaddr*)&servaddr,sizeof(servaddr));
n=recvfrom(sockfd,buffer,10000,0,NULL,NULL);
buffer[n]=0;
printf("Received:%s\n",buffer);
return 0;
}
Your main problem is that you are not checking the results of any of your operations on the sockets, so it is entirely possible that the server or client is reporting an error message that makes the answer to your problem obvious.
In particular, if the server fails to bind or listen to the listen socket, it will just go into an infinite loop making failed accepts, reads and writes forever.
I suspect that, what happens is that when you restart the server, the previous socket is still in the TIME_WAIT state, so it can't bind to the port. You can get around this by using the following after creating the socket:
int reuseaddr = 1;
if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&reuseaddr,sizeof(reuseaddr))==-1)
{
fprintf(stderr, "%s",strerror(errno));
exit(1);
}
Note how the above checks the return result and reports an error on failure. You need to do this or similar after every call to socket(), listen(), bind(), connect(), recvfrom(), sendto() and close().
Note, how I put close() in that list. You really must call it on the connect socket when you are finished with it, especially on the server or you will leak the file descriptor in connfd.
I am creating a server daemon in c that accepts numerous simultaneous connections, and the clients will be sending data to the server. I currently have each client connection being spawned into a new thread. I am seeing that accept() will sometimes (not always) return the ID of existing connection which (obviously) causes a wide variety of issues, including segmentation faults.
I even turned off the socket option SO_REUSEADDR to make sure that wasn't the case. Whenever a single client makes numerous consecutive calls, everything is fine (conid in my code below increments - 5,6,7,8,9, etc...). But whenever more than one client ties to simultaneously connect, sometimes conid gets duplicated (an example from one run: 5,6,7,7,8,9,10,10,10,11,12,12, ...).
I'm wondering how accept() can return an existing connection?? It would make sense if I was calling accept() within more than one thread, but as you can see below it only exists in the main process thread. On the other hand, I never experienced this issue with select(), so maybe it is an issue with threading??? At this point, I've tried just about everything I can think of, but it's apparent to me I'm just missing something
Edit: edited code to show that mystruct wasn't being free'd in the while loop, and (hopefully) provide more insight.
Edit #2: per request, I have posted the full source of my example.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdarg.h>
#include <time.h>
#include <errno.h>
#include <netdb.h>
//this is my test structure
struct mystruct_ {
int id; //only id for testing
};
typedef struct mystruct_ mystruct;
//error logging function
void merr(const char *msg, ...) {
//get the time
time_t t;
time(&t);
//grab this function's arguments
va_list args;
char buf[BUFSIZ];
va_start(args,msg);
//build the message
vsprintf(buf,msg,args);
//output the message
printf(" ERROR :: %s\n",buf);
//that's it!
va_end(args);
}
//this function handles the threads
void *ThreadedFunction(void *arg) {
//get the passed structure
mystruct *test = (mystruct *)arg;
//print conid -- this is where I am seeing the duplicates
printf("my connection id is %d\n",test->id);
// do some stuff, like: pull vars out of mystruct
int nbytes;
char buf[256];
while(1) {
if((nbytes=recv(test->id, buf, sizeof buf, 0)) <= 0) {
//handle break in connection
close(test->id);
} else {
//for this example, just print out data from client to make my point
buf[nbytes] = 0;
printf("%s",buf);
}
}
}
//main just sets up the connections and creates threads
int main(int argc, char *argv[])
{
char *port = "1234";
//get ready for connection
struct sockaddr_storage addr;
socklen_t addrsize = sizeof addr;
struct addrinfo hints, *res, *ai, *p;
int sockfd, conid, rv;
int yes = 1;
//
//load up address structs with getaddrinfo():
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
if((rv = getaddrinfo(NULL, port, &hints, &ai))!= 0) {
merr("failed to bind port '%s': %s\n",port,gai_strerror(rv));
exit(1);
}
//
//bind the port
for(p=ai; p!=NULL; p=p->ai_next) {
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if(sockfd<0) continue;
//setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); //commented for testing
if(bind(sockfd,p->ai_addr,p->ai_addrlen)<0) { close(sockfd); continue; }
break;
}
//if we don't have p, it means server didn't get bound
if(p==NULL) { merr("failed to bind port '%s' (reason unknown)",port); exit(2); }
freeaddrinfo(ai); //all done with this
//
// listen to the (now bounded) socket:
if(listen(sockfd,10)==-1) { merr("listen; errmsg: \"%s\"",strerror(errno)); exit(3); }
// bind(), listen(), etc... blah blah blah
mystruct test[1024]; //just for testing
printf("Ready and Listening...\n");
while(1) {
conid = accept(sockfd, (struct sockaddr *)&addr, &addrsize);//get a connection
test[conid].id = conid;
pthread_t p;
pthread_create(&p,NULL,ThreadedFunction,&test[conid]); //create new thread
}
}
This is broken:
while(1) {
conid = accept(sockfd, (struct sockaddr *)&addr, &addrsize);//get a connection
test[conid].id = conid;
pthread_t p;
pthread_create(&p,NULL,ThreadedFunction,&test[conid]); //create new thread
}
pthread_t p; declares an opaque handle on the stack which pthread_create will fill in. That handle's lifetime must last until you call pthread_join or pthread_detach.
In this case, the storage for that pthread_t is probably being reused, messing up the passing of the argument to the thread function. At least, that is my guess.
Try calling pthread_detach after pthread_create.
accept returns a file descriptor that my be reused. As your ThreadedFunction never terminates when done with a file descriptor you will get a race condition. So after the close statement put return;