I am writing a simple client and server program in C. I am able to send date from client to server. But, I am not able to send acknowledge from server to client.
/*******************udpserver.c*****************/
int main(int argc, char *argv[])
{
/* Variable and structure definitions. */
int sd, rc;
struct sockaddr_in serveraddr, clientaddr;
clientaddrlen = sizeof(clientaddr);
int serveraddrlen = sizeof(serveraddr);
char buffer[100];
char *bufptr = buffer;
int buflen = sizeof(buffer);
if((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("UDP server - socket() error");
exit(-1);
}
printf("UDP server - socket() is OK\n");
memset(&serveraddr, 0x00, serveraddrlen);
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(0);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
if((rc = bind(sd, (struct sockaddr *)&serveraddr, serveraddrlen)) < 0) {
perror("UDP server - bind() error");
close(sd);
exit(-1);
}
int addr_len = sizeof(serveraddr);
if (getsockname(sd, (struct sockaddr *) &serveraddr, &addr_len)<0) {
perror("Error getting socket name.\n");
return -1;
}
printf("Using IP %s and port %d\n", inet_ntoa(serveraddr.sin_addr), ntohs(serveraddr.sin_port));
printf("UDP server - Listening...\n");
rc = recvfrom(sd, bufptr, buflen, 0, (struct sockaddr *)&clientaddr, &clientaddrlen);
if(rc < 0) {
perror("UDP Server - recvfrom() error");
close(sd);
exit(-1);
}
printf("UDP Server received the following:\n \"%s\" message\n", bufptr);
printf("UDP Server replying to the UDP client...\n");
rc = sendto(sd, bufptr, buflen, 0, (struct sockaddr *)&clientaddr, clientaddrlen);
if(rc < 0) {
perror("UDP server - sendto() error");
close(sd);
exit(-1);
}
printf("UDP Server - sendto() is OK...\n");
close(sd);
exit(0);
}
My UDPClient program:
/****************udpclient.c********************/
int main(int argc, char *argv[])
{
/* Variable and structure definitions. */
int sd, rc;
struct sockaddr_in serveraddr, clientaddr;
int serveraddrlen = sizeof(serveraddr);
char server[255];
char buffer[100];
char *bufptr = buffer;
int buflen = sizeof(buffer);
struct hostent *hostp;
memset(buffer, 0x00, sizeof(buffer));
/* 36 characters + terminating NULL */
memcpy(buffer, "Hello! A client request message lol!", 37);
if((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("UDP Client - socket() error");
exit(-1);
}
else
printf("UDP Client - socket() is OK!\n");
if(argc != 3) {
/*Use default hostname or IP*/
printf("UDP Client - Usage <Server hostname or IP>\n");
exit(0);
}
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
hostp = gethostbyname(argv[1]);
if(hostp == (struct hostent *)NULL) {
printf("HOST NOT FOUND --> ");
printf("h_errno = %d\n", h_errno);
exit(-1);
}
else {
printf("UDP Client - gethostname() of the server is OK... \n");
printf("Connected to UDP server\n");
}
memcpy(&serveraddr.sin_addr, hostp->h_addr, sizeof(serveraddr.sin_addr));
rc = sendto(sd, bufptr, buflen, 0, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
if(rc < 0) {
perror("UDP Client - sendto() error");
close(sd);
exit(-1);
}
else
printf("UDP Client - sendto() is OK!\n");
printf("Waiting a reply from UDP server...\n");
rc = recvfrom(sd, bufptr, buflen, 0, (struct sockaddr *)&serveraddr, &serveraddrlen);
if(rc < 0) {
perror("UDP Client - recvfrom() error");
close(sd);
exit(-1);
} else {
printf("UDP client received the following: \"%s\" message\n", bufptr);
}
close(sd);
exit(0);
}
When running the two programs, I am getting the following output:
UdpServer:
$ ./UdpServer
UDP server - socket() is OK
Using IP 0.0.0.0 and port 49932
UDP server - Listening...
UDP Server received the following:
"Hello! A client request message lol!" message
UDP Server replying to the UDP client...
UDP Server - sendto() is OK...
UdpClient:
$ ./UdpClient MyPC 49932
UDP Client - socket() is OK!
UDP Client - gethostname() of the server is OK...
Connected to UDP server
UDP Client - sendto() is OK!
Waiting a reply from UDP server...
UdpClient program is stuck at this point. Could anyone please explain what the problem is?
You might like to use select() to make the process wait until data is avaibale for reading:
...
{
fd_set rfds;
int retval;
FD_ZERO(&rfds);
FD_SET(sd, &rfds);
retval = select(sd+1, &rfds, NULL, NULL, NULL);
if (retval == -1)
perror("select()");
else
printf("Data is available for reading now.\n");
...
}
...
If the server and client are running on the same machine, give
$ ./UdpClient localhost 49932
instead of
$ ./UdpClient MyPC 49932
else
$ ./UdpClient <server-IP-address> 49932
Also in the server code,
clientaddrlen = sizeof(clientaddr);
should be
int clientaddrlen = sizeof(clientaddr);
But I guess that's just a copy-paste mistake.
Related
I am currently coding a small chat application in C for learning network.
I develop using the Transmission Control Protocol with socket in C. I was able to connect to my server with a client not coded by myself (on local network). Now telnet succeed to connect to my chat server(so with server and telnet client on the same computer) and I can send and receive message BUT my very simple client cannot connect to it.
Since the begining I use port 9002 and right now I am trying to connect with IPv6 address ::1.
Here the "accept client" code of my server:
int main(void)
{
//Create the socket
int sock = socket(AF_INET6, SOCK_STREAM, 0);
printf("Socket créer\n");
//Set up the socket interface
struct sockaddr_in6 sin6 = { 0 };
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(PORT);
sin6.sin6_addr = in6addr_any;
//Bind the socket on the port
if(bind(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr_in6)) == SO_ERROR)
{
perror("bind()");
errx(EXIT_FAILURE, "Fail to bind");
}
//Make the sockey listen the port
if(listen(sock, MAX_CLIENT) == SO_ERROR)
{
perror("listen()");
errx(EXIT_FAILURE, "Fail to listen");
}
printf("Socket listening\n");
int csock;
size_t clientID = 0;
--snip--
while(1)
{
struct sockaddr_in6 csin6;
memset(&csin6, 0, sizeof(struct sockaddr_in6));
int sin6size = sizeof(struct sockaddr_in6);
//Accept a communication
printf("Wait for communication\n");
csock = accept(sock, (struct sockaddr *) &csin6, &sin6size);
printf("Connection accepted\n");
char msg[16];
sprintf(msg, "CONNECTED - %zu\n", clientID);
send(csock, msg, sizeof(msg), 0);
printf("Client %zu connected\n", clientID);
//Handle client
--snip--
}
So this is a basic connection with socket using connected communication. The server handle several client in the while loop thanks to threading.
Here the code of the client:
void *sender(void *arg)
{
int socket = (int)(long)arg;
char buffer[BUFF_SIZE];
while(1)
{
scanf("%s", buffer);
send(socket, buffer, strlen(buffer), 0);
bzero(buffer, BUFF_SIZE);
}
}
int main(int argc, char *argv[])
{
if(argc < 2)
errx(EXIT_FAILURE, "Usage: ./client <server ip>\n");
//Create the socket
int sock = socket(AF_INET6, SOCK_STREAM, 0);
struct hostent *hostinfo = NULL;
hostinfo = gethostbyname2(argv[1], AF_INET6);
if(hostinfo == NULL)
errx(EXIT_FAILURE, "Can't connect to the server\n");
//Set up the socket interface
struct sockaddr_in6 sin6 = { 0 };
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(PORT);
sin6.sin6_addr = *(struct in6_addr *)hostinfo->h_addr;
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)
{
perror("connect()");
errx(EXIT_FAILURE, "Fail to connect");
}
printf("Connection established\n");
pthread_t sending;
if(pthread_create(&sending, NULL, sender, (void *)(long)sock) != 0)
printf("Fail to create a thread\n");
//Handle reception
char buffer[BUFF_SIZE];
int n;
while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
{
buffer[n] = '\0';
printf("%s", buffer);
}
printf("Erreur: %d\nConnection broken\n", n);
pthread_cancel(sending);
close(sock);
return EXIT_SUCCESS;
}
So I start the client with:
~ ./client ::1
The output is the following:
Connection established
Error: -1
Connection broken
While the server is still "Waiting for communication". This means that the server do not accept the connection but the client succeed to connect.
Thank you for you help.
It is probably already the connect(), which fails here:
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)
SO_ERROR is not meant to be used here, but as a socket option when retrieving the error when an asynchronous connect fails. A (synchronous) connect() returns -1 on error and sets errno, so do
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == -1) {
...
Later, the recv here:
while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
fails with errno ENOTCONN, since the connection failed beforehand.
The same SO_ERROR mistake is present at various locations in your server code; it is possible, that already the bind() there fails! The call to listen() will then autobind it to a free ephemereal port, so the call as well as the call to accept() will succeed.
Why can the call to bind() fail? You might have to set the socket option SO_REUSEADDR when (re-)starting the server, otherwise it might refuse to use a recently bound port if connections are still in TIME_WAIT state. Place this directly before the bind() call:
int one = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
This might help.
I am building a client-server socket simulation to emulate DHCP. I have a client that receives input from the user, then sends a request via UDP to Server1. If Server1 does not hold the requested information, it contacts Server2 via TCP. If Server2 does not hold the information, it contacts Server3. Server3 then sends information to Server2 then Server1 then on to the Client
My code works for Client --> Server1 --> Server2 --> Server1 --> Client, but it fails when I try to add Server3.
Server3 successfully receives the connection and data from Server2, and the send is successful I believe. However, the recv on server 2 returns -1.
Here is my Server3 send code:
while ((rqst = accept(svc,(struct sockaddr *) &client_addr, &alen)) < 0) {
/* we may break out of accept if the system call */
/* was interrupted. In this case, loop back and */
/* try again */
}
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
recvlen = recv(rqst, buf, BUFSIZE - 1, 0);
if (send(rqst, "Hello Server2!\0", BUFSIZE, 0) < 0) { /* Not real message, but this works */
perror("sendto");
}
My Server2 recv code is here
int port = SERVICE_PORT3; /* default: whatever is in port.h */
char *host = "localhost"; /* default: this host */
if (!conn_and_send(host, port, buf, fd3)) { /* connect fd3 is global int */
exit(1); /* something went wrong */
}
else {
char serv3_buf[BUFSIZE];
int serv3_recvlen = recv(fd3, serv3_buf, BUFSIZE - 1, 0);
printf("The recv length from serv3 is: %d\n", serv3_recvlen); /* prints -1*/
}
This is my conn_and_send function
int conn_and_send(char *host, int port, char* request, int fd_sock)
{
struct hostent *hp; /* host information */
unsigned int alen; /* address length when we get the port number */
struct sockaddr_in myaddr; /* our address */
struct sockaddr_in servaddr; /* server address */
printf("conn(host=\"%s\", port=\"%d\")\n", host, port);
if ((fd_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("cannot create socket");
return 0;
}
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(0);
if (bind(fd_sock, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
perror("bind failed");
return 0;
}
alen = sizeof(myaddr);
if (getsockname(fd_sock, (struct sockaddr *)&myaddr, &alen) < 0) {
perror("getsockname failed");
return 0;
}
printf("local port number = %d\n", ntohs(myaddr.sin_port));
memset((char*)&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
hp = gethostbyname(host);
if (!hp) {
fprintf(stderr, "could not obtain address of %s\n", host);
return 0;
}
memcpy((void *)&servaddr.sin_addr, hp->h_addr_list[0], hp->h_length);
if (connect(fd_sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("connect failed");
return 0;
}
printf("Getting ready to send: %s\n", request);
if (send(fd_sock, request, strlen(request), 0) < 0) {
perror("sendto");
exit(1);
}
return 1;
}
Sorry to post so much code. I tried to include only relevant snippets.
What am I doing wrong, and if you can see no problems besides my poor C coding, why does C hate me?! :P
I created a server socket in C. This is the most basic stuff like what you would fine in a simple TCP server example. Server code is below. I also created a client socket that runs on the host machine. Code also below. However, for some reason the client is not able to connect to the server. The IP address I used is the same as the one under the entry eth0 from the "ip addr" command. The network adapter of the VM is a bridged connection.
The exact same code works when both client and server run on the same machine (the host).
Thank you!
Server code:
int sockfd;
int clientfd;
struct sockaddr_in self;
struct sockaddr_in client_addr;
int addrlen = sizeof (client_addr);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket");
return EXIT_FAILURE;
}
printf("Socket descriptor is: %d\n", sockfd);
memset(&self, 0, sizeof (self));
self.sin_family = AF_INET;
self.sin_port = htons(MY_PORT);
self.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr*) &self, sizeof (self)) != 0) {
perror("socket--bind");
return EXIT_FAILURE;
}
if (listen(sockfd, 20) != 0) {
perror("socket--listen");
return EXIT_FAILURE;
}
clientfd = accept(sockfd, (struct sockaddr*) &client_addr, &addrlen);
printf("%s:%d connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
Client Code:
int sock;
struct sockaddr_in server;
//struct sockaddr_in client;
struct hostent *hp;
//char buf[BUFFER_SIZE];
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
die(6, "Opening stream socket");
printf("Client socket file descriptor is: %d\n", sock);
memset(&server, (char) 0, sizeof (server));
server.sin_family = AF_INET;
hp = gethostbyname(host_name);
if (!hp) {
//sprintf(buf, "%s: unknown host\n", host_name);
die(8, "%s: unknown host\n", host_name);
}
memcpy(hp->h_addr, &server.sin_addr, hp->h_length);
server.sin_port = htons((u_short) SERVER_PORT);
/* Try to connect */
if ((connect(sock, (struct sockaddr *) &server, sizeof (server))) < 0)
die(7, "%s", "Failed to connect stream socket\n");
I'm working on a networking project. I can successfully send a single message from my client program over to my server program. However, when I send a second message, the server apparently isn't receiving it. I say this because the client program generates output to suggest that the message was sent, but the server shows no reaction at all.
I'm thinking that I am doing something wrong with either select() or FD_ISSET(). Can anyone see what I am doing wrong? Thanks.
int main(int argc, char *argv[]) {
int sockfd, newfd;
struct sockaddr_in clientAddr;
unsigned int recvLen;
socklen_t addr_size = sizeof clientAddr;
fd_set read_set;
struct timeval tv;
char buffer[BUFFSIZE];
// prepare the address struct for the first client
bzero(&clientAddr,sizeof(clientAddr)); //zero the struct
clientAddr.sin_family = AF_INET; //address family (ipv4)
clientAddr.sin_port = htons(SERVER_PORT); //sets port to network byte order
clientAddr.sin_addr.s_addr = INADDR_ANY;
// create a listening connection to listen for requests from clients
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stdout, "Cannot create socket for client 0.\n");
fprintf(stdout, "Terminating program\n\n");
exit(1);
}
if (bind(sockfd, (struct sockaddr *)&clientAddr, sizeof(clientAddr)) < 0) {
fprintf (stdout, "Binding failed for client 0\n\n");
perror("bind failed");
exit (1);
}
if (listen(sockfd, 10) < 0) {
fprintf (stdout, "Listen() failed\n");
perror("listen() failed");
exit (1);
}
// accept the connection
if ((newfd = accept(sockfd, (struct sockaddr *)&clientAddr, &addr_size)) < 0) {
fprintf(stdout, "Error accepting inbound data from client 0\n");
perror(" accept() failed");
exit(EXIT_FAILURE);
}
// initialize the fd set
FD_ZERO(&read_set);
FD_SET(newfd, &read_set); // adding our socket to the set
tv.tv_sec = 0;
tv.tv_usec = TIMEOUT * 1000;
while (1) {
if ( select(newfd+1, &read_set, NULL, NULL, &tv) == -1) {
perror("select failure");
fprintf(stdout, "errno: %d\n", errno);
exit(EXIT_FAILURE);
}
if (FD_ISSET(newfd, &read_set)) {
bzero(buffer, BUFFSIZE);
recv(newfd, &buffer, BUFFSIZE, 0);
fprintf(stdout, "Received message: %s\n", buffer);
}
}
return 0;
}
After each select you need call FD_ZERO(&read_set); FD_SET(newfd, &read_set); again.
So just move those functions into the loop, before select.
I need my server to broadcast a message (not that it matters but it contains its IP/port info). What I have currently is the working server broadcast, code below. I'm not sure about setting up the client because usually I would use the IP/port of the server which the client doesn't have until it receives the broadcast. The client never receives anything. Can someone tell me what is wrong.
Server:
struct sockaddr_in server, bcast;
int sockfd;
int blen = sizeof(bcast);
int svrlen = sizeof(server);
char buf[BUFLEN];
if((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){
printf("Socket error.\n");
exit(1);
}
int broadcastPermission = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (void *)&broadcastPermission,sizeof(broadcastPermission)) < 0){
printf("Error setting socket options.");
}
memset(&bcast, 0, sizeof(bcast));
bcast.sin_family = AF_INET;
bcast.sin_port = htons(PORT);
bcast.sin_addr.s_addr = htonl(INADDR_ANY);
string bcastIP = BCASTIP;
if(inet_aton("255.255.255.255", &bcast.sin_addr) == 0){
printf("Broadcast Address error.");
exit(1);
}
if (bind(sockfd, (struct sockaddr*)&server, sizeof(server)) == -1){
printf("Port error.\n");
exit(1);
}
fflush(stdout);
if(int bytes = sendto(sockfd, ipinfo, sizeof(ipinfo), 0, (struct sockaddr*)&bcast, blen) == -1){
printf("Broadcast send error.");
}
else{
printf("Sent"):
}
Client:
struct sockaddr_in server;
int sockfd;
int bytes;
int svrlen = sizeof(server);
char buf[BUFLEN]
if((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){
printf("Socket error.\n");
exit(1);
}
memset((char *)&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(BPORT);
server.sin_addr.s_addr = htonl(INADDR_ANY);
while(1){
printf("Waiting for broadcast...\n\n");
fflush(stdout);
memset(buf,0,BUFLEN);
bytes = recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&server, (socklen_t*)&svrlen);
printf("Received");
}
Your client is not calling bind() on the socket before trying to receive data.
http://cs.baylor.edu/~donahoo/practical/CSockets/code/BroadcastReceiver.c shows the following example which you may find helpful:
void DieWithError(char *errorMessage); /* External error handling function */
int main(int argc, char *argv[])
{
int sock; /* Socket */
struct sockaddr_in broadcastAddr; /* Broadcast Address */
unsigned short broadcastPort; /* Port */
char recvString[MAXRECVSTRING+1]; /* Buffer for received string */
int recvStringLen; /* Length of received string */
if (argc != 2) /* Test for correct number of arguments */
{
fprintf(stderr,"Usage: %s <Broadcast Port>\n", argv[0]);
exit(1);
}
broadcastPort = atoi(argv[1]); /* First arg: broadcast port */
/* Create a best-effort datagram socket using UDP */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
DieWithError("socket() failed");
/* Construct bind structure */
memset(&broadcastAddr, 0, sizeof(broadcastAddr)); /* Zero out structure */
broadcastAddr.sin_family = AF_INET; /* Internet address family */
broadcastAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
broadcastAddr.sin_port = htons(broadcastPort); /* Broadcast port */
/* Bind to the broadcast port */
if (bind(sock, (struct sockaddr *) &broadcastAddr, sizeof(broadcastAddr)) < 0)
DieWithError("bind() failed");
/* Receive a single datagram from the server */
if ((recvStringLen = recvfrom(sock, recvString, MAXRECVSTRING, 0, NULL, 0)) < 0)
DieWithError("recvfrom() failed");
recvString[recvStringLen] = '\0';
printf("Received: %s\n", recvString); /* Print the received string */
close(sock);
exit(0);
}
I need my server to broadcast a message (not that it matters but it contains its IP/port info).
That sounds a lot like service discovery. You should really use the standard mDNS/Zeroconf protocol for that. You can use the Avahi library for that (or use the Avahi service on Linux or Zeroconf on MacOS X).