I'm working on a university project, in which I have to connect a raspberry pi to an Android smartphone to control 2 motors.
We are new to socket programming, so we started out with an example we found on wikibooks and tried to modify in to our needs. We're now facing the problem, that the connection between server and client is very arbitrary and unstable, sometimes connecting, and after a brief disconnect doesnt connect again. The weird thing (for me) is, that after we edit the code above the part responsible for connection:
/* bind serv information to mysocket */
bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr));
/* start listening, allowing a queue of up to 2 pending connection */
listen(mysocket, 2);
consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
like inserting in a printf, the next time we launch the programm, everthing does work, sometimes two or three times, and then it just stops connecting.
I've searched all over google and so for a similar problem, but I haven't found an equivalent, so I turn to you directly now.
This is code for our server running on the raspberry pi, which also serves as a network hotspot:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <bcm2835.h>
#define PORTNUM 5298
#define MAXRCVLEN 1000
#define PIN9 RPI_GPIO_P1_21
#define PIN10 RPI_GPIO_P1_19
#define PIN11 RPI_GPIO_P1_23
#define PIN22 RPI_GPIO_P1_15
int setpins();
int forward();
int backward();
int main(int argc, char *argv[])
{
char msg[] = "Connected!\n";
char testchar[] = "stillthere?";
char quitstring[] = "quit";
char *recbuf;
int qflag = 0;
int lflag = 0;
int mysocket, consocket, len; /* socket used to listen for incoming connections */
struct sockaddr_in dest; /* socket info about the machine connecting to us */
struct sockaddr_in serv; /* socket info about our server */
socklen_t socksize = sizeof(struct sockaddr_in);
memset(&serv, 0, sizeof(serv)); /* zero the struct before filling the fields */
serv.sin_family = AF_INET; /* set the type of connection to TCP/IP */
serv.sin_addr.s_addr = htonl(INADDR_ANY); /* set our address to any interface */
serv.sin_port = htons(PORTNUM); /* set the server port number */
mysocket = socket(AF_INET, SOCK_STREAM, 0);
/* bind serv information to mysocket */
bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr));
/* start listening, allowing a queue of up to 2 pending connection */
listen(mysocket, 2);
consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
if (!bcm2835_init()) return 1;
setpins();
while(consocket)
{
printf("Incoming connection from %s - sending welcome\n", inet_ntoa(dest.sin_addr));
send(consocket, msg, strlen(msg), 0);
while (!qflag && !lflag) {
// Do something when connection is lost: SO_KEEPALIVE?
// if (!send(consocket,testchar, strlen(testchar), 0)) lflag = 1;
recbuf = malloc (MAXRCVLEN+1);
len = recv(consocket, recbuf, MAXRCVLEN, 0);
recbuf[len] = '\0';
if (len > 0) printf("Client sent %s (%d bytes). \n", recbuf, len);
if (recbuf[0] == 'v') forward(); // this function lets our car drive forward
if (recbuf[0] == 'r') backward();// this one backwards ;)
// Leave this loop if the client sends you the quitstring
if (!strcmp (recbuf, quitstring)) qflag = 1;
free(recbuf);
}
if (qflag) break;
listen(mysocket, 1);
consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
}
close(consocket);
close(mysocket);
printf("sockets closed\n");
return EXIT_SUCCESS;
}
One line in there
// if (!send(consocket,testchar, strlen(testchar), 0)) lflag = 1;
is our idea to test wether the connection is still up, is this viable?
And this is the client code, thats not in Java yet but in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define MAXRCVLEN 500
#define PORTNUM 5298
int main(int argc, char *argv[])
{
char buffer[MAXRCVLEN + 1]; /* +1 so we can add null terminator */
int len, mysocket;
struct sockaddr_in dest;
mysocket = socket(AF_INET, SOCK_STREAM, 0);
memset(&dest, 0, sizeof(dest)); /* zero the struct */
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr("192.168.42.1"); /* set destination IP number */
dest.sin_port = htons(PORTNUM); /* set destination port number */
do {
connect(mysocket, (struct sockaddr *)&dest, sizeof(struct sockaddr));
len = recv(mysocket, buffer, MAXRCVLEN, 0);
}while(len < 0);
/* We have to null terminate the received data ourselves */
buffer[len] = '\0';
// Received
printf("Received %s (%d bytes).\n", buffer, len);
// send:
char msg[] = " ";
do{
scanf("%s",msg);
printf("Sending Msg to %s \n", inet_ntoa(dest.sin_addr));
send( mysocket, msg, strlen(msg),0);
}while (strcmp(msg,"quit"));
close(mysocket);
return EXIT_SUCCESS;
}
Any ideas what we did wrong?
Thanks in advance!
Unless what you actually, really want to learn is low-level berkeley socket manipulation, I'd suggest you look at libevent or a similar library.
The structure of your main loop is a little unusual. You can clearly only handle one connection at a time, and you don't cope well with any connection attempts that happened while you were servicing a previous connection.
bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr));
bind can fail, e.g. if another process has recently had the socket open and the OS hasn't finished cleaning up use of the port. You can change this behavior, but you should still check, from die.net's bind manpage
Return Value
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
so
if(bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr))) {
perror("bind failed");
exit(1);
}
listen() only needs to be called once, but also needs to be checked
if(listen(mysocket, 2)) {
perror("listen failed");
exit(1);
}
after this, if you are content to do the single-service approach, then you can do the following:
mysocket = socket(AF_INET, SOCK_STREAM, 0);
if(mysocket < 0) {
perror("socket failed");
exit(1);
}
if(bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr))) {
perror("bind failed");
exit(1);
}
if(listen(mysocket, 2)) {
perror("listen failed");
exit(1);
}
for (;;) {
consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
if(consocket < 0) // might return if the connection has already gone away.
continue;
if (!sendGreeting(consocket)) {
// sendGreeting should return -1 if it was unable to send, 0 if successful
while (!readLoop(consocket, recvBuf, MAXRCVLEN))
;
}
close(consocket);
}
readLoop would then be something like:
int readLoop(int socket, char* buffer, size_t bufSize) {
int len = recv(socket, buffer, bufSize);
if (len > 0)
return processBuffer(socket, buffer, len);
if (len < 0 && (errno == EINTR || errno == EAGAIN))
return 0; // do-over
return -1;
}
make sure that processBuffer also returns 0 or -1 accordingly.
As I mentioned above, there are still problems with this approach, but it's not my intent here to teach you everything you need to know about sockets in one pass :) If you want to further develop your socket knowledge, your next stop should be learning about select or poll with non-blocking sockets so that you can host multiple sockets and service them as they become active.
Generally, you should use tcpdump/wireshark to see what packets are seen by you Rpi, and strace to see what your program does. My first guess about your connections sometimes not working would be loss of packets. By using wired LAN (Ethernet), you could rule this possibility out.
But the example server code that you're using is a rather bad example. Even if you only want to accept a single client connection at a time, your server should not use blocking waits for any remote message. You should read about using non-blocking I/O, select or poll, and look at examples using these. Also, please read about SO_REUSEADDR, you probably need that one in your server as well.
This line code
char msg[] = " ";
do{
scanf("%s",msg);
will fail miserably if the number of bytes scanned in is larger then 1 character, as msg provides exactly two bytes (from which one is always used as 0-terminator). Feeding more would write out of the bounds of msg and doing so will provoke undefined behaviuor.
To fix this providing at least a minimum of 255 characters to so:
char msg[256] = "";
do{
scanf("%255s",msg);
Related
Help me to correct this program I want to create a server that can run indefinitely and can serve many clients and for that, I am using a select system call for UDP (User Datagram Protocol) application.
My issue is that this code is running for multiple clients in a different session that means after running for one client it stops and again when I start the server again then it can serve another client also.
I want my code to work indefinitely in one session only and serve as many clients as I want.
Server Code:-
'''
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define port1 8080
#define MAXN 1024
#define TRUE 1
int main(){
int sockfd,sockfd1;
struct sockaddr_in servaddr,cliaddr;
char buffer[MAXN];
char buff[MAXN];
int max_clients=2,valread,new_socket;
char *hello = "Hello Client";
char *message = "hiiii Server";
struct timeval timeout;
timeout.tv_sec = 20;
timeout.tv_usec = 0;
//create socket 2
sockfd = socket(AF_INET, SOCK_DGRAM,0);
if(sockfd<0){
perror("Error Creating Socket0");
exit(1);
}
//memset(&servaddr, 0, sizeof(servaddr));
//memset(&cliaddr, 0, sizeof(cliaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port1);
servaddr.sin_addr.s_addr = INADDR_ANY;
if(bind(sockfd, (const *)&servaddr, sizeof(servaddr))<0){
perror("Error in binding0 ");
exit(1);
}
//Use Select......
//I have created 2 socket having file deescriptor sockfd and sockfd1
int s;
int client_socket[2]={0,0};
fd_set readfds;
while(){
FD_ZERO(&readfds);
FD_SET(sockfd,&readfds);
//Let's say sockfd is max_fd
int max_fd = sockfd,sd,activity;
for(int i=0;i<2;i++){
sd = client_socket[i];
if(sd>0){
FD_SET(sd,&readfds);
}
if(sd>max_fd)
max_fd = sd;
}
activity = select( max_fd + 1 , &readfds , NULL , NULL , &timeout);
if ((activity < 0))
{
printf("select error");
}
int addrlen = sizeof(servaddr);
//If something happened on the master socket ,
//then its an incoming connection
if (FD_ISSET(sockfd, &readfds))
{
//inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d\n " , new_socket , inet_ntoa(servaddr.sin_addr) , ntohs
(servaddr.sin_port));
//send new connection greeting message
if( send(new_socket, message, strlen(message), 0) != strlen(message) )
{
perror("send");
}
puts("Welcome message sent successfully");
//add new socket to array of sockets
for (int i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
printf("Adding to list of sockets as %d\n" , i);
break;
}
}
}
//else its some IO operation on some other socket
for (int i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
//Check if it was for closing , and also read the
//incoming message
if ((valread = read( sd , buffer, 1024)) == 0)
{
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&servaddr , \
(socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" ,
inet_ntoa(servaddr.sin_addr) , ntohs(servaddr.sin_port));
//Close the socket and mark as 0 in list for reuse
//close( sd );
client_socket[i] = 0;
}
//Echo back the message that came in
else
{
//set the string terminating NULL byte on the end
//of the data read
buffer[valread] = '\0';
send(sd , buffer , strlen(buffer) , 0 );
}
}
}
}
return 0;
}
'''
This is one of the Client Code and this code is running :-
'''
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define PORT 8080
#define MAXN 1024
// Driver code
int main() {
int sockfd;
char buffer[MAXN];
char *hello = "Hello from Multipleclient";
struct sockaddr_in servaddr;
// Creating socket file descriptor
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("Error in socket creation");
exit(1);
}
memset(&servaddr, 0, sizeof(servaddr));
// Filling server information
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = INADDR_ANY;
int n, len;
sendto(sockfd, (const char *)hello, strlen(hello),
MSG_CONFIRM, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
printf("Hello message sent.\n");
n = recvfrom(sockfd, (char *)buffer, MAXN,
MSG_WAITALL, (struct sockaddr *) &servaddr,
&len);
buffer[n] = '\0';
printf("Server : %s\n", buffer);
close(sockfd);
return 0;
}
Some minor things to start with:
In the client code, you do not initialize len before passing it to recvfrom. Also, it is of the wrong type (int instead of socklen_t). This can be corrected by defining len as socklen_t len = sizeof(servaddr); However, since you do not use the length or address anywhere, you can just pass in NULL for both. Also, UDP does not support MSG_WAITALL, so pass 0 instead for the flags. recvfrom(sockfd, (char *)buffer, MAXN, 0, NULL, NULL).
In the client code, you fill in the server IP address as IPADDR_ANY, i.e. 0.0.0.0, which is only valid when calling bind. You are calling sendto. When specifying a destination address, you probably want IPADDR_LOOPBACK for the local computer.
In the server code, the main while() loop is missing a condition inside the parenthesis, so the code does not even compile. You probably want while(1) for an infinite loop.
In the server code, in the call to bind, you are casting to the wrong type. (const *) means (const int *), but you want (const struct sockaddr *).
The biggest problem:
Based on the comments and code in the server code, you seem to think that UDP communication has persistent connections, and try to save client_socket values for these. However, UDP does not have persistent connection. There is no such thing as a client socket in this context. select does not tell you that a new "connection" is ready. Instead, it tells you that data has been received on your one and only UDP socket (sockfd). This is entirely unlike TCP, where you accept a connection that lasts until one side terminates it.
From the comments in the server code, it seems that you intend for clients to have persistent state in the server, at least enough to be recognized when they send more datagrams (otherwise they would always get the welcome message).
A possible way to make this work is the following:
// create and bind a UDP socket as you already do;
// initialize and empty list of clients;
while(1) {
struct sockaddr_in cliaddr;
socklen_t cliaddr_len = sizeof(cliaddr);
recvfrom(sockfd, buffer, bufferlen, /*flags*/ 0, (struct sockaddr *)&cliaddr, &cliaddr_len);
// check whether cliaddr is in your list;
if (!is_in_list) {
// this is a new client
// add to list of clients;
// send welcome message;
}
// do something else, maybe echo back the buffer contents;
}
You will notice that the code does not actually use select anymore. select is unnecessary if you have nothing to do while waiting, and you only listen to one socket. If you are doing other stuff not shown in the question, you can add the select back at the top of the infinite loop, and only handle the UDP socket if sockfd is set in the readfds from select.
Also note that the client cannot actually receive answers from the server, since there is no persistent connection, and the client has not passed any socket to bind. And also note that UDP messages may get lost without warning, and you should make sure your code can deal with that. It seems that this client-server-strategy would be easier to implement using TCP.
As a side note, it is strongly recommended to enable warnings in your compiler. That would have caught the wrong type for the address length variables, as well as told you that new_socket is used but never set. It is polite to fix all warnings before posting a question, unless of course the question is about the warning.
I have such a task, I need to write the “client” code so that the message from the “client” is sent to the server (which was created by my teacher, ip “127.0.0.1”). After the message arrives at the server (for example, “Nursultan Nazarbayev”, the server will reply “ok” and the client should send “quit”)
I'm just learning C. How to make a break with the server? I wanted to send "quit", but this did not work, there was a constant error, how can I do this?
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
char message[2048];//=(char*)malloc(sizeof(char));// transmission message
char buf[sizeof(message)];
int port,ch;
//----------------------------------------------------------------------------
if(argc!=3){
printf("Wrong number of arguments!\nThere must be 2 arguments (Port, server ip-address)!\n");
exit(0);
}
int sock; // socket descriptor
struct sockaddr_in addr; // structure with address
struct hostent* hostinfo;
port = atoi(argv[1]);
hostinfo = argv[2];
sock = socket(AF_INET, SOCK_STREAM, 0); // create TCP socket
if(sock < 0)
{
perror("socket");
exit(1);
}
// Specify server parameters
addr.sin_family = AF_INET; // Internet domains
addr.sin_port = htons(port); // or any other port ...
addr.sin_addr.s_addr=inet_addr("hostinfo");
// addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
//addr.sin_addr.s_addr = inet_addr(host_ip);
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) // establishing a connection to the server
{
perror("Connection");
exit(2);
}
while(1){//WHILE <---
//----------------------------------------------------------------------------
printf("Enter a message to the server (To exit: quit): ");
if (!strcmp(gets(message), "quit")){close(sock);return 0;}
//----------------------------------------------------------------------------
printf("sending a message to the server...\n");
send(sock, message, sizeof(message), 0); // sending a message to the server
int bytes_read = 0;
printf("Message Waiting\n");
bytes_read = recv(sock, buf, sizeof(message), 0);
printf("received %d bytes\tMessage: %s\n", bytes_read, buf); // receiving a message from the server
}//END_WHILE
return 0;
}
This probably is wrong:
addr.sin_addr.s_addr=inet_addr("hostinfo");
You are passing the literal string, "hostinfo" to the inet_addr() function. Meanwhile, you have a variable named hostinfo, to which you assign a string value, but you never use it anywhere in the program.
Maybe you meant to do this instead:
addr.sin_addr.s_addr=inet_addr(hostinfo);
P.S., I like long, descriptive names. If that was my program, the name of the variable would be something like, server_address_as_string.
I'm trying to implement communication by UDP protocol, and I'm getting an error: "Error sending: Address family not supported by protocol". I've checked in Google for this problem but couldn't managed to find answer.
Please be patient, I'm only starting my adventure with coding in C.
Here is a C code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#define BUFLEN 512
// define function that deals with errors
void error(const char *msg)
{
perror(msg); // print error msg
exit(1); // exit the main() function
}
int main(int argc, char *argv[])
{
struct sockaddr_in serv1_addr, serv2_addr, cli1_addr, cli2_addr; //definicja struktur adresów servera i clienta
struct hostent *server; //defines host addres struct
int cl1_sockfd, se1_sockfd, se2_sockfd, i, c1len = sizeof(cli1_addr), c2len = sizeof(cli2_addr), recv_len, portno1,portno2; // creates inits
int cli1_len = sizeof(cli1_addr);
int cli2_len = sizeof(cli2_addr);
char buf[BUFLEN];
if (argc < 4) {
fprintf(stderr,"ERROR, no port provided\n"); // deal with wrong port
exit(1);
}
//tworzenie soceketu servera
if ((se1_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){
error("socket1"); //if socket() return -1 -- error
}
if ((se2_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){
error("socket2"); //if socket() return -1 -- error
}
//zero out the structure
memset( &serv1_addr, 0, sizeof(serv1_addr)); //put zero into structure
memset( &serv2_addr, 0, sizeof(serv2_addr)); //put zero into structure
portno1 = atoi(argv[2]); // get port number
portno2 = atoi(argv[3]);
serv1_addr.sin_family = AF_INET; // specify address family (IPv4)
serv1_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv1_addr.sin_port = htons(portno1); // set port number
serv2_addr.sin_family = AF_INET; // specify address family (IPv4)
serv2_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv2_addr.sin_port = htons(portno2); // set port number
if(connect(se1_sockfd,(struct sockaddr *) &serv1_addr, sizeof(serv1_addr)) < 0)
error ("ERROR connecting1"); //if connection failed
if(connect(se2_sockfd,(struct sockaddr *) &serv2_addr, sizeof(serv2_addr)) < 0)
error ("ERROR connecting2"); //if connection failed
while(1) //inf loop
{
printf("Please enter the message: "); //write the msg to socket
bzero(buf, 512); //fill buffer with zeros
fgets(buf, 512, stdin); //read into buffer
if( sendto( se1_sockfd, buf, BUFLEN, 0, (struct sockaddr*) &cli1_addr, cli1_len) < 0)
error ("Error sending1");
if( sendto( se2_sockfd, buf, BUFLEN, 0, (struct sockaddr*) &cli2_addr, cli2_len) < 0)
error ("Error sending2");
if (recvfrom(se1_sockfd, buf, BUFLEN, 0, (struct sockaddr *) &cli1_addr, &cli1_len) == -1){
error("recivfrom()1"); //if reciving failed -- error
}
printf("Data: %s\n", buf);
if (recvfrom(se2_sockfd, buf, BUFLEN, 0, (struct sockaddr *) &cli2_addr, &cli2_len) == -1){
error("recivfrom()2"); //if reciving failed -- error
}
printf("Data: %s\n", buf);
}
close(se1_sockfd);
close(se2_sockfd);
return 0;
}
Thanks for your help. ;)
Your issue is likely because of uninitialized destination address. sendto() takes destination address as the one before the last argument. But you are trying to provide not-initialized address (like for recvfrom())
if( sendto( se1_sockfd, buf, BUFLEN, 0, (struct sockaddr*) &cli1_addr, cli1_len) < 0)
error ("Error sending1");
^^^
Try serv1_addr instead ?
Also need to provide appropriate size.
One more thing. As long as you use sendto() - no need to perform connect(). UDP is connectionless and connect() only establishes default destination address for those who is going to use send() on such socket. But this is not your case because you provide destination address each time you call sendto(). Even more - you may use different addresses each time.
P.S. Reference: sendto()
First off, this is homework, so please no outright answers. I am writing a back and forth chat program in C. I'm extremely new to C (just started learning for this class). Currently I have three files:
server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include "chat.h"
#define SERVER_PORT 1725
#define MAX_PENDING 5
#define MAX_LINE 256
int main()
{
struct sockaddr_in sin;
char buf[MAX_LINE];
int len;
int s, new_s;
struct chat_packet packet;
/* build address data structure */
bzero((char *)&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(SERVER_PORT);
/* setup passive open */
if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("simplex-talk: socket");
exit(1);
}
if ((bind(s, (struct sockaddr *)&sin, sizeof(sin))) < 0)
{
perror("simplex-talk: bind");
exit(1);
}
listen(s, MAX_PENDING);
/* wait for connection, then receive and print text */
while(1)
{
if ((new_s = accept(s, (struct sockaddr *)&sin, &len)) < 0)
{
perror("simplex-talk: accept");
exit(1);
}
/* Stay in the following loop until CTRL+C */
while (len = recv(new_s, &packet, sizeof(packet), 0))
{
fputs(packet.sender_name, stdout);
fputs(": ", stdout);
fputs(packet.data, stdout);
fputs("\nYou: ", stdout);
while (fgets(buf, sizeof(buf), stdin))
{
if(strlen(buf) > 144)
{
printf("Your message is too long. Please enter a new message.\n");
continue;
}
else
{
buf[MAX_LINE-1] = '\0';
strncpy(packet.data,buf,144);
char sender[8] = "Mason"; /*should be argv[index of name]*/
strncpy(packet.sender_name, sender, 8);
send(new_s, &packet, sizeof(packet),0);
}
}
}
close(new_s);
}
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "chat.h"
#define SERVER_PORT 1725
#define MAX_LINE 256
int main(int argc, char * argv[])
{
FILE *fp;
struct hostent *hp;
struct sockaddr_in sin;
char *host;
char buf[MAX_LINE];
int s;
int len;
struct chat_packet packet;
if (argc==2)
{
host = argv[1];
}
else
{
fprintf(stderr, "usage: simplex-talk host\n");
exit(1);
}
/* translate host name into peer's IP address */
hp = gethostbyname(host);
if (!hp) {
fprintf(stderr, "simplex-talk: unknown host: %s\n", host);
exit(1);
}
/* build address data structure */
bzero((char *)&sin, sizeof(sin));
sin.sin_family = AF_INET;
bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
sin.sin_port = htons(SERVER_PORT);
/* active open */
if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("simplex-talk: socket");
exit(1);
}
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
perror("simplex-talk: connect");
close(s);
exit(1);
}
/* main loop: get and send lines of text */
while (fgets(buf, sizeof(buf), stdin))
{
if(strlen(buf) > 144)
{
printf("Your message is too long. Please enter a new message.\n");
continue; /*This allows the user to re-enter a message post-error*/
}
else
{
buf[MAX_LINE-1] = '\0';
strncpy(packet.data, buf, 144);
char sender[8] = "Abby"; /*should be argv[index of name]*/
strncpy(packet.sender_name, sender, 8);
send(s, &packet, sizeof(packet), 0);
recv(s, &packet, sizeof(packet),0);
fputs(packet.sender_name, stdout);
fputs(": ", stdout);
fputs(packet.data, stdout);
fputs("\nYou: ", stdout);
}
}
}
chat.h
#include <stdint.h> /* Needed for unsigned types */
#define MAX_DATA_LEN 144 /* So we are on 16-bit boundary */
#define USER_NAME_LEN 8
/* You must send this packet across the socket. Notice there are
* no pointers inside this packet. Why?*/
struct chat_packet {
u_short version; /* 16 bits -- Set to version 2 in code */
char sender_name[8]; /* 64 bits */
char data[MAX_DATA_LEN]; /* Message goes in here */
};
Everything except what is in the client and server while loops were given to me by my instructor. The base part of the assignment is getting back-and-forth chat functionality. I'm running everything in PuTTY using the command line. I duplicate the session and run client in one and server in the other. To run:
./client serverName
./server
I am able to go back and forth one time, and then nothing else sends or receives. I am still able to type, but the two sessions cannot see each other's messages past the first back and forth. I am not sure where my code is wrong. Any advice would be appreciated, as I'm very new to the language. Thanks in advance!
Okay, here's my hint: Think about what happens when you recv() zero characters. Also, check what happens when the server calls accept() vs. when the client calls connect().
You might also want to check the return values of your recv() calls more judiciously. (and send(), for that matter; if a call can fail, check its return value!) Here's a hint from the man recv page:
RETURN VALUES
These calls return the number of bytes received, or -1 if an error occurred.
Also, if you aren't familiar with a debugger (such as gdb), I would recommend learning it. In a pinch, you might consider adding printf() statements to your code, to figure out what is happening.
Also, think about where your "blocking calls" are. If you're not familiar with what it means to be a "blocking call", we call it "blocking" when you call a function, and that function doesn't return ("blocks") until some specified thing happens. For example, your accept() will block until a connection is accepted. Your fgets() will block until a line of text is received. send() would block if you've already sent too much data, and the buffer is full. recv() would block until you've received the specified number of bytes. recv() also has a behavior you might not expect, that you may need to account for:
If no messages are available at the socket, the receive call waits for a
message to arrive, unless the socket is nonblocking (see fcntl(2)) in
which case the value -1 is returned and the external variable errno set
to EAGAIN. The receive calls normally return any data available, up to
the requested amount, rather than waiting for receipt of the full amount
requested; this behavior is affected by the socket-level options
SO_RCVLOWAT and SO_RCVTIMEO described in getsockopt(2).
In your case, your packets might be small enough that you won't run into cases where you have to reassemble them yourself. But it couldn't hurt to check.
I think that gives you some avenues to explore...
I'm just starting out on networking programming in c. I followed a simple tutorial to create a server which accepts a connection and prints out the message sent from the client.
the client takes an argument as the address of the server.
I'm not sure how to specify the address of the server? Is it my machine name?
I'm running the server in one terminal and trying to connect from another. Thanks for any help :)
here's the server code
`#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
#define BUFLEN 1500
int fd;
ssize_t i;
ssize_t rcount;
char buf[BUFLEN];
printf("test1");
fd = socket (AF_INET,SOCK_STREAM,0);
if (fd == -1){
printf("Oh dear, something went wrong with read()! %s\n", strerror(errno));
}
struct sockaddr_in addr;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
addr.sin_port = htons(500);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
printf("cannot bind socket");
}
if (listen(fd, 20) == -1) {
printf("unable to listen");
}
int connfd;
struct sockaddr_in cliaddr;
socklen_t cliaddrlen = sizeof(cliaddr);
connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
if (connfd == -1) {
printf("unable to accept");
}
rcount = read(fd, buf, BUFLEN);
if (rcount == -1) {
// Error has occurred
}
for (i = 0; i < rcount; i++) {
printf("%c", buf[i]);
}
}`
printf("test1");
You should add "\n" (newline char) at the end of printed string, so that it prints immediately. Without "\n", printf() buffers its output, and you don't see them.
addr.sin_port = htons(500);
Ports 0 - 1023 are called "well known port" and reserved to the system (root). You should use port 1024 or greater for a test program like this. Changing it from 500 to 1500 (for example) binds successfully.
(You don't see the error message "cannot bind socket" because it has no "\n", as I said above.)
rcount = read(fd, buf, BUFLEN);
You should read from connfd, instead of fd. With these changes, it worked for me.
(I used "telnet localhost 1500" as a client.)