How would I go about making this udpclient asynchronous using pthreads? - c

How would I go about making this udpclient asynchronous using pthreads? I want to make sure UDP datagram won't be lost and also don't want the client program to wait forever and not be able to send any more messages
/*udpclient.c program */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN
#include <winsock.h>
#include <windows.h>
#endif
#ifndef WIN
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
/* Here are some details of the sockaddr_in structure and the sockaddr structure
These declarations are copied from winsock.h
struct in_addr { this struct holds a 32 bit IP address
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
#define s_addr S_un.S_addr
struct sockaddr_in { notice this structure is 16 bytes long
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct sockaddr { this generic address structure is 16 bytes long, too!
u_short sa_family;
char sa_data[14];
};
*/
/* we have to send on the same port the server is listening on */
#define PORT 20009
/* simple upd client */
int main()
{
#ifdef WIN
SOCKET sock;
#else
int sock;
#endif
int size;
int nbytes, flags;
int i;
char * cp;
#ifdef WIN
WSADATA wsaData;
int nCode;
#endif
char buffer[100];
char str_addr[20]; /* holds the chars of an IP address */
struct sockaddr_in target_pc, me;
/* magic call to initialize the network I/O code - only Microsoft requires this */
#ifdef WIN
if((nCode = WSAStartup(MAKEWORD(1,1), &wsaData)) != 0){
printf("Opps! WSA error %d\n",nCode);
return -1;
}
#endif
/* create a socket to send on */
sock = socket(PF_INET,SOCK_DGRAM,0);
if(sock < 0) {
printf("socket error = %d\n", sock);
return -1;
}
/* we fill in the address family and port, but we do not know the destination IP address yet */
target_pc.sin_family = PF_INET;
target_pc.sin_port = htons(PORT);
/* fill in my address and port */
me.sin_family = PF_INET;
me.sin_port = htons(0);
me.sin_addr.s_addr = htonl(INADDR_ANY);
i = bind(sock, (struct sockaddr *) &me, sizeof(me));
if( i < 0) {
printf("bind result: %d\n", i);
return -1;
}
nbytes = 99;
while(1){
printf("Enter the target IP address: ");
cp = fgets(str_addr,19,stdin);
/* remove the \n */
str_addr[strlen(str_addr)-1] = '\0';
/* the inet_addr function converts a string form of IP address to a 32 binary integer */
target_pc.sin_addr.s_addr = inet_addr(&str_addr[0]);
printf("Enter your message: ");
cp = fgets(buffer,99,stdin);
/* get the string length so we send exactly this many characters */
nbytes = strlen(buffer);
flags = 0;
size = sendto(sock, (char *) buffer, nbytes,flags,(struct sockaddr *)&target_pc,sizeof(target_pc));
printf("msg size = %d size = %d\n", nbytes, size);
//added
int addrlen = sizeof(target_pc);
size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&target_pc,&addrlen);
if((size > 0) && (size < 99)){
buffer[size] = '\0'; //add the null byte so buffer now holds a string
i = puts((char *) buffer); // write this string to the display
}
}
#ifdef WIN
system("PAUSE");
#endif
return 0;
}
/udpserver.c program/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#ifdef WIN
#include <winsock.h>
#include <windows.h>
#endif
#ifndef WIN
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
#define PORT 20009
/* simple upd server
this program receives short messages (<99 characters) from any IP address
and writes them to the display
be sure to use the linker line option "-l wsock32"
*/
int main()
{
/* first define a socket
a socket is an I/O port like a file descriptor
*/
#ifdef WIN
SOCKET sock; /* SOCKET is a typedef for a structure */
#else
int sock;
#endif
int size;
int nbytes, flags;
#ifdef WIN
int addrlen;
#else
socklen_t addrlen;
#endif
int i;
/* char loopback[20]="127.0.0.1"; */
#ifdef WIN
WSADATA wsaData; /* This is struct holds Windows required data */
int nCode;
#endif
char buffer[100];
struct sockaddr_in server; /* this holds my IP address and port info */
struct sockaddr_in from; /* this holds the same info for the sender of the packet
I received */
/* the call to WSAStartup is Windows magic */
#ifdef WIN
if((nCode = WSAStartup(MAKEWORD(1,1), &wsaData)) != 0){
printf("Opps! WSA error %d\n",nCode);
exit;
}
#endif
/* create a socket called sock. It is a datagram socket */
sock = socket(AF_INET,SOCK_DGRAM,0);
if(sock < 0){
printf("socket error = %d\n", sock);
return -1;
}
server.sin_family = AF_INET; /* initialize the server address family */
server.sin_addr.s_addr = htonl(INADDR_ANY); /* notice this struct within a struct */
/* printf("%x\n",server.sin_addr.s_addr); */
server.sin_port = htons(PORT);
/* associate the socket with the address structure - this is called binding */
i = bind(sock, (struct sockaddr *) &server, sizeof(server));
if( i < 0) {
printf("bind result: %d\n", i);
return -1;
} else
printf("Simple UDP server is ready!\n\n");
nbytes = 99; /* receive packets up to 99 bytes long */
flags = 0; /* must be zero or this will not work! */
while(1){
/* the recvfrom function is a read and the arguments are:
sock - the socket we are reading
buffer - array into which to read the data
nbytes - read up to this many bytes
flags - used for special purposes - not needed here
from - sockaddr struct to hold the IP address and port of the sender of the packet
addrlen - the size of the sockaddr struct written by this function
*/
addrlen = sizeof(from);
size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&from, &addrlen);
if((size > 0) && (size < 99)){
buffer[size] = '\0'; /* add the null byte so buffer now holds a string */
i = puts((char *) buffer); /* write this string to the display */
}
//echo message back to client
if(sock < 0) {//
printf("socket error = %d\n", sock);//
return -1;//
}//
sendto(sock, buffer, nbytes, flags, (struct sockaddr *)&from,addrlen); //
}
#ifdef WIN
system("PAUSE");
#endif
return 0;
}

We could create two threads: one for the sendto (that waits for the user input) and the other for recvfrom(). Next, we can have the recvrom() use Pthread condvar (by calling pthread_cond_wait() on a condvar and a Pthread mutex) and wait. When the user provides an input, we can sendto (which is not really blocking) and then call pthread_cond_signal() to wake up the other thread.
You could certainly simply this, if you wanted. If your application permits, you could completely skip the pthread_cond_wait() since recvfrom() is anyways a blocking call. So, this way, recvfrom() would block but then it would go out of sync with the send calls. The other option is to use the main() thread for the sendto() thread -- in that case, you would just need one additional thread for the recv calls.

Related

When requesting time from server I get a Segmentation fault (core dumped). How can I resolve this?

I am writing a program where the client sends the server a time request. I also want to send my name and get the server to echo it back. So far the program will echo my name but then I get a Segmentation fault (core dumped) where the time should be display. I have attached the code for the clien and server and also a screenshot of the terminal.
SERVER CODE
#include <stdio.h> /* I/O functions */
#include <string.h> /* string functions */
#include <stdlib.h> /* C standard functions */
#include <sys/socket.h> /* socket functions */
#include <sys/types.h> /* library of basic types */
#include <netinet/in.h> /* library of Internet address functions */
#include <arpa/inet.h> /* Internet operations */
#include <time.h> /* time functions */
#define PORT 8080 /* server port # */
#define BUFFSIZE 200 /* buffer size */
int main()
{
int sockfd;
int addrlen;
char buffer[BUFFSIZE];
struct sockaddr_in server;
struct sockaddr_in client;
time_t current_time;
/* Populate socket data structures with IP address and port number */
memset((char *) &server, 0, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
/* Create a UDP socket; returns -1 on failure */
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if (sockfd == -1) {
printf("Socket error\n");
exit(1); /* Exit on error */
}
/* Bind the socket address */
if ((bind(sockfd,(struct sockaddr*)&server,sizeof(struct sockaddr_in))) == -1) {
printf("Server bind error\n");
exit (1); /* Exit on error */
}
/* Status message */
printf("The server is listening on port: %d\n", PORT);
printf("Waiting for client request...\n");
printf("Press CTRL + C to exit\n");
while(1) {
addrlen = sizeof(struct sockaddr_in);
recvfrom(sockfd, buffer,BUFFSIZE, 0,(struct sockaddr *)&client, (socklen_t *)&addrlen);
current_time = time(NULL);
memcpy(buffer + strlen(buffer) + 1, &current_time, sizeof(current_time));
sendto(sockfd, buffer, strlen(buffer) + 1 + sizeof(current_time), 0, (struct sockaddr *)&client, addrlen);
}
exit(0);
} /* End of time server program */
CLIENT CODE
#include <stdio.h> /* I/O functions */
#include <string.h> /* string functions */
#include <stdlib.h> /* C standard functions */
#include <sys/socket.h> /* socket functions */
#include <sys/types.h> /* library of basic types */
#include <netinet/in.h> /* library of Internet address functions */
#include <arpa/inet.h> /* Internet operations */
#include <time.h> /* time functions */
#define BUFFSIZE 200 /* buffer size */
int main(int argc, char *argv[])
{
int sockfd;
int addrlen;
char buffer[BUFFSIZE] = "GET TIME\r\n";
struct sockaddr_in server;
struct sockaddr_in client;
char *servIP = argv[1]; // Server IP address from command line
int servPort = atoi(argv[2]); // Server port number from command line
char *name = argv[3];
time_t current_time;
/* Check that two arguments were passed on the command line */
if (argc != 4) {
printf("Usage: udp-time-client [IP address] [Port] [Name] \n");
exit(1);
}
/* Populate server socket data structure with IP address and port number */
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(servPort);
server.sin_addr.s_addr = inet_addr(servIP);
/* Populate client socket data structure with IP address and port number */
memset((void *)&client, '\0', sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(servPort);
client.sin_addr.s_addr = inet_addr(servIP);
/* Create a UDP socket; returns -1 on failure */
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if (sockfd == -1) {
printf("Socket error\n");
exit(1);
}
/* Status message */
printf("Client is sending on IP address %s port: %d\n", servIP, servPort);
/* Send the time request to the server */
addrlen = sizeof(struct sockaddr_in);
strcpy(buffer, name);
sendto(sockfd, buffer, (int)strlen(buffer) + 1, 0, (struct sockaddr *)&server, addrlen);
printf("Request sent to server\n");
/* Receive the time request from server */
recvfrom(sockfd, (char *) buffer, sizeof(buffer), 0, (struct sockaddr *)&server, (socklen_t *)&addrlen);
/* Print the name received from the server */
printf("\n The name received from the server:%s\n", buffer);
memcpy((void *)current_time, buffer + strlen(buffer) + 1, sizeof(current_time));
/* Print the time received from the server */
printf("\n The time received from the server:%s\n", ctime(&current_time));
exit(0);
} /* End of time client program */
Screenshot of terminal As you can see, my name is echoed back but I get the error where the time should be
memcpy((void *)current_time, ...);
should be
memcpy(&current_time, ...);

UDP Socket Programming - recvfrom() one Port and sendto() other Port

UDP Socket Programming - Server listening on Port 5000 - Client listening on Port 6000
recvfrom() from one Port - 5000
sendto() to other Port - 6000 to the same client.
Server.c
#include <stdio.h> /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket() and bind() */
#include <arpa/inet.h> /* for sockaddr_in and inet_ntoa() */
#include <stdlib.h> /* for atoi() */
#include <string.h> /* for memset() */
#include <unistd.h> /* for close() */
#define MAXSIZE 255 /* Longest string */
#define SRC_PORT 5000
#define DST_PORT 6000
int main(int argc, char *argv[])
{
int sock; /* Socket */
struct sockaddr_in ServAddr; /* Local address */
struct sockaddr_in ClntAddr; /* Client address */
socklen_t CliAddrLen; /* Length of incoming message */
char recBuffer[MAXSIZE]; /* Buffer for echo string */
int recvMsgSize; /* Size of received message */
int i;
/* Create socket for sending/receiving datagrams */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
DieWithError("socket() failed");
/* Construct local address structure */
memset(&ServAddr, 0, sizeof(ServAddr)); /* Zero out structure */
ServAddr.sin_family = AF_INET; /* Internet address family */
ServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
ServAddr.sin_port = htons(SRC_PORT); /* Local port */
/* Construct address structure */
memset(&ClntAddr, 0, sizeof(ClntAddr)); /* Zero out structure */
ClntAddr.sin_family = AF_INET; /* Internet address family */
ClntAddr.sin_addr.s_addr = inet_addr("192.168.1.*");
ClntAddr.sin_port = htons(DST_PORT);
/* Bind to the local address */
if (bind(sock, (struct sockaddr *) &ServAddr, sizeof(ServAddr)) < 0)
DieWithError("bind() failed");
for (;;) /* Run forever */
{
printf("Listening on UDP:5000 \n");
/* Set the size of the in-out parameter */
cliAddrLen = sizeof(ClntAddr);
/* Block until receive message from a client */
if ((recvMsgSize = recvfrom(sock, recBuffer, MAXSIZE, 0,(struct sockaddr *) &ClntAddr, &cliAddrLen)) < 0)
DieWithError("recvfrom() failed") ;
printf("Handling Client: %s\n", inet_ntoa(ClntAddr.sin_addr));
printf("Received Data: %s",recBuffer);
printf("\n");
/* Send response datagram back to the client */
if (sendto(sock, recBuffer, MAXSIZE, 0, (struct sockaddr *) & ClntAddr, sizeof(ClntAddr)) < 0)
DieWithError("sendto() failed");
}
/* NOT REACHED */
}
It works perfectly. Client and Server programming using different ports for sending and receiving the data.
Thank you
Regards
this is wrong
lntAddr.sin_addr.s_addr = inet_addr("CLIENT_IP");
inet_addr takes a dotted ip address not a host name

Recv() not working in separate thread, C socket programming

I am having some issues with the recv() function returning a -1 in a C program with threading. The basis of the program is to receive a few request packets in one thread and having a second thread send out a multicast to all registered clients.
Below is the code for my server:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <arpa/inet.h>
#include <pthread.h>
#define SERVER_PORT 5654
#define MAX_LINE 256
#define MAX_PENDING 5
/*structure of the packet*/
struct packet{
short type;
char data[MAX_LINE];
};
struct data_packet{
short header;
char data[MAX_LINE];
};
/* structure of Registration Table */
struct registrationTable{
int port;
char name[MAX_LINE];
int req_no;
};
struct global_table{
int sockid;
int reqno;
};
void *join_handler(struct global_table *rec){
int new_s;
struct packet packet_reg;
new_s = rec->sockid;
printf("In thread: %i\n",new_s);
printf("In thread: %i\n",rec->reqno);
if(recv(new_s,&packet_reg,sizeof(packet_reg),0)<0){
printf("\ncouldnt receive first reg packet\n");
exit(1);
}
pthread_exit(NULL);
}
int main(int argc, char* argv[])
{
/* initilizing all of the packets*/
struct packet packet_reg;
struct registrationTable table[10];
struct global_table record[20];
struct sockaddr_in sin;
struct sockaddr_in clientAddr;
char buf[MAX_LINE];
int s, new_s;
int len;
int i;
struct hostent *he;
struct in_addr **addr_list;
pthread_t threads[2];
/* setup passive open */
if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0){
perror("tcpserver: socket");
exit(1);
}
/* 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);
if(bind(s,(struct sockaddr *)&sin, sizeof(sin)) < 0){
perror("tcpclient: bind");
exit(1);
}
listen(s, MAX_PENDING);
/* wait for connection, then receive and print text */
while(1){
if((new_s = accept(s, (struct sockaddr *)&clientAddr, &len)) < 0){
perror("tcpserver: accept");
exit(1);
}
/* print the port of the client*/
printf("\n Client's port is %d \n", ntohs(clientAddr.sin_port));
/* receive the first registration packet*/
if(recv(new_s,&packet_reg,sizeof(packet_reg),0)<0){
printf("\ncouldnt receive first reg packet\n");
exit(1);
}
struct global_table client_info;
client_info.sockid = ntohs(clientAddr.sin_port);
client_info.reqno = 1;
pthread_create(&threads[0],NULL,join_handler, &client_info);
}
}
Client:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#define SERVER_PORT 5654
#define MAX_LINE 256
/*structure of the packet*/
struct packet{
short type;
char data[MAX_LINE];
};
struct data_packet{
short header;
char data[MAX_LINE];
};
int main(int argc, char* argv[])
{
struct packet packet_reg;
struct hostent *hp;
struct sockaddr_in sin;
char *host;
char buf[MAX_LINE];
int s;
int len;
char hostname[1024];
hostname[1023] = '\0';
if(argc == 2){
host = argv[1];
}
else{
fprintf(stderr, "usage:newclient server\n");
exit(1);
}
/* translate host name into peer's IP address */
hp = gethostbyname(host);
if(!hp){
fprintf(stderr, "unkown host: %s\n", host);
exit(1);
}
/* active open */
if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0){
perror("tcpclient: socket");
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);
if(connect(s,(struct sockaddr *)&sin, sizeof(sin)) < 0){
perror("tcpclient: connect");
close(s);
exit(1);
}
/* main loop: get and send lines of text
all you have to do to start the program is
enter any key */
while(fgets(buf, sizeof(buf), stdin)){
/* Find the hostname and print it*/
gethostname(hostname, 1023);
printf("Hostname: %s\n", hostname);
/* populate the info for the first registration packet*/
packet_reg.type = htons(121);
strcpy(packet_reg.data,hostname);
/*send the registration packet to the server*/
if(send(s,&packet_reg,sizeof(packet_reg),0)<0){
printf("\nsend failed\n");
exit(1);
}
/* Print the contents of the first registration packet*/
printf("Sent 1st reg packet data: %s\n",packet_reg.data );
printf("Sent 1st reg packet type: %i\n",ntohs(packet_reg.type));
/* create the second registration packet.
I created separate packets for this so
it was clearer*/
packet_reg.type = htons(121);
strcpy(packet_reg.data,hostname);
/*send the second registration packet to the server*/
if(send(s,&packet_reg,sizeof(packet_reg),0)<0){
printf("\nsend failed\n");
exit(1);
}
/* Print the contents of the second registration packet*/
printf("Sent 2nd reg packet data: %s\n",packet_reg.data );
printf("Sent 2nd reg packet type: %i\n",ntohs(packet_reg.type));
}
}
So Basically, I am creating the connection and wait to receive the first registration packet (packet_reg). This works and I receive the packet. I then send control of the program to the thread. However, while the "rec" variable correctly passes the information, the subsequent receive does not work and exits with a value less than 0.
Other information: The packets are all sent and received correctly, but the client's port, printed from
printf("\n Client's port is %d \n", ntohs(clientAddr.sin_port));
is listed as 0. I am not sure if this is a problem, but the code works fine when all of the receives are in the main function.
Another issue could be that I get the following warning:
passing argument 3 pf pthread_create from incompatible pointer type expected 'void * (*) (void *)' but argument of type 'void * (*) (struct global_table*)'
I have researched this warning and know that it has to do with receiving the data as void and then casting. However, the data is being sent to the thread properly when I print from there to check.
Basically, the problem is that while I can receive the packets from the client outside the thread, with the same statements, when I am inside the thread the packets are not received and recv() returns -1.
I accidentally set the receive to the port and not the socket. I am a dummy. I know that a lot of you were telling me how bad the code is constructed regarding TCP conventions. I am building off of code for an assignment, nothing I can do about the professor telling us that this is the way to do it.

Segmentation Fault in UDP

I got a segmentation fault problem when I write a client-server project in UDP. It happens on server side, when I receive a packet from client and going to send an ACK back. I tried to search the solutions and got UDP Server giving Segmentation Fault and C concurrent UDP socket , weird segmentation fault, but seems both of those are not the answer I'm looking for.
Here is my server side code
#include <ctype.h> /* for toupper */
#include <stdio.h> /* for standard I/O functions */
#include <stdlib.h> /* for exit */
#include <string.h> /* for memset */
#include <sys/socket.h> /* for socket, sendto, and recvfrom */
#include <netinet/in.h> /* for sockaddr_in */
#include <unistd.h> /* for close */
#define STRING_SIZE 1024
#define SERV_UDP_PORT 12311
int main(void) {
int sock_server;
struct sockaddr_in server_addr;
unsigned short server_port;
struct sockaddr_in client_addr;
unsigned int client_addr_len;
char sentence[STRING_SIZE];
char modifiedSentence[STRING_SIZE];
unsigned int msg_len;
int bytes_sent, bytes_recd;
unsigned int i;
struct Pkt
{
short length;
short seqnum;
char databytes[80];
};
struct Pkt* pkt;
int j ; //for loop
int seq;
short num_of_bytes;
//char ack_num[2];
struct Ack
{
short ack_num;
};
struct Ack* ack;
/* open a socket */
if ((sock_server = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("Server: can't open datagram socket\n");
exit(1);
}
/* initialize server address information */
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl (INADDR_ANY);
server_port = SERV_UDP_PORT;
server_addr.sin_port = htons(server_port);
/* bind the socket to the local server port */
if (bind(sock_server, (struct sockaddr *) &server_addr,
sizeof (server_addr)) < 0) {
perror("Server: can't bind to local address\n");
close(sock_server);
exit(1);
}
/* wait for incoming messages in an indefinite loop */
printf("Waiting for incoming messages on port %hu\n\n",
server_port);
client_addr_len = sizeof (client_addr);
for (;;) {
bytes_recd = recvfrom(sock_server, pkt, sizeof(*pkt), 0, (struct sockaddr *) &client_addr, &client_addr_len);
ack->ack_num = pkt->seqnum;
printf("%02d\n", ack->ack_num);
num_of_bytes = pkt->length;
printf("The sequence number is: %d\n", ack->ack_num);
printf("Received Sentence is: %s\n with length %d\n\n", pkt->databytes, num_of_bytes);
msg_len = 3;
/* send message */
bytes_sent = sendto(sock_server, (struct Ack*)&ack, msg_len, 0, (struct sockaddr*) &client_addr, client_addr_len); //Here is the segmentation fault comes from
}
}
I'm not really good at C, so forgive me if the code is silly.
Please point out anything wrong or just looks weird.
Thanks in advance for any help.
pkt is pointer to a Pkt, but you haven't initialized it. Likewise with ack. You can either a) malloc a Pkt and assign the result to pkt, or b) change pkt to be a Pkt structure (rather than a pointer). The second option would look something like:
struct Pkt pkt;
struct Ack ack;
bytes_recd = recvfrom(sock_server, &pkt, sizeof(pkt), 0, (struct sockaddr *) &client_addr, &client_addr_len);
ack.ack_num = pkt.seqnum;
printf("%02d\n", ack.ack_num);
num_of_bytes = pkt.length;
printf("The sequence number is: %d\n", ack.ack_num);
printf("Received Sentence is: %s\n with length %d\n\n", pkt.databytes, num_of_bytes);
/* send message */
bytes_sent = sendto(sock_server, &ack, sizeof(ack), 0, (struct sockaddr*) &client_addr, client_addr_len);

How to use pthreads for sending and receiving in a udpclient in C

I'm trying to modify a client program that my professor supplied so that it will use pthreads for the functions sendto() and recvFrom(). I was able to timetag it and have the client receive as well as send messages and have my udpserver.c echo back messages. But I can't get my pthreads to work. I'm kinda new to pthreads. This is the error I got:
/tmp/cciYoHsc.o:udpclient.c:(.text+0x253): undefined reference to `_sendMessage'
/tmp/cciYoHsc.o:udpclient.c:(.text+0x2f2): undefined reference to `_recvMessage'
collect2: ld returned 1 exit status
I think it might have something to do with all the ifdef/endif keywords. I'm not really sure what all they do. This is my program udpclient.c
/*UPDATED*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#ifdef WIN
#include <winsock.h>
#include <windows.h>
#endif
#ifndef WIN
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
/* Here are some details of the sockaddr_in structure and the sockaddr structure
These declarations are copied from winsock.h
struct in_addr { this struct holds a 32 bit IP address
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
#define s_addr S_un.S_addr
struct sockaddr_in { notice this structure is 16 bytes long
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct sockaddr { this generic address structure is 16 bytes long, too!
u_short sa_family;
char sa_data[14];
};
*/
/* we have to send on the same port the server is listening on */
#define PORT 20009
/* simple upd client */
//prototypes
void *sendMessage( void *ptr );
void *recvMessage( void *ptr );
typedef struct info {
int size;
char buffer[100];
int nbytes,flags,addrlen;
} info;
//size = sendto(sock, (char *) buffer, nbytes,flags,(struct sockaddr *)&target_pc,(int)ptr);
int main()
{
#ifdef WIN
SOCKET sock;
#else
static int sock;
#endif
static int size;
static int nbytes, flags;
static int i;
static char * cp;
#ifdef WIN
WSADATA wsaData;
int nCode;
#endif
static char buffer[100];
static char str_addr[20]; /* holds the chars of an IP address */
static struct sockaddr_in target_pc, me;
/* magic call to initialize the network I/O code - only Microsoft requires this */
#ifdef WIN
if((nCode = WSAStartup(MAKEWORD(1,1), &wsaData)) != 0)
{
printf("Opps! WSA error %d\n",nCode);
return -1;
}
#endif
/* create a socket to send on */
sock = socket(PF_INET,SOCK_DGRAM,0);
if(sock < 0)
{
printf("socket error = %d\n", sock);
return -1;
}
/* we fill in the address family and port, but we do not know the destination IP address yet */
target_pc.sin_family = PF_INET;
target_pc.sin_port = htons(PORT);
/* fill in my address and port */
me.sin_family = PF_INET;
me.sin_port = htons(0);
me.sin_addr.s_addr = htonl(INADDR_ANY);
i = bind(sock, (struct sockaddr *) &me, sizeof(me));
if( i < 0)
{
printf("bind result: %d\n", i);
return -1;
}
nbytes = 99;
//create threads
pthread_t sendT;
pthread_t recvT;
while(1)
{
struct timeval te;
struct timeval te2;
info *sendInfo;
info *recvInfo;
printf("Enter the target IP address: ");
cp = fgets(str_addr,19,stdin);
/* remove the \n */
str_addr[strlen(str_addr)-1] = '\0';
/* the inet_addr function converts a string form of IP address to a 32 binary integer */
target_pc.sin_addr.s_addr = inet_addr(&str_addr[0]);
printf("Enter your message: ");
cp = fgets(buffer,99,stdin);
/* get the string length so we send exactly this many characters */
nbytes = strlen(buffer);
flags = 0;
int addrlen = sizeof(target_pc);
sendInfo->size = size;
sendInfo->buffer = buffer;
sendInfo->nbytes = nbytes;
sendInfo->flags = flags;
sendInfo->addrlen = addrlen;
pthread_create( &sendT, NULL, sendMessage, (void*) addrlen);
//size = sendto(sock, (char *) buffer, nbytes,flags,(struct sockaddr *)&target_pc,sizeof(target_pc));
//time
gettimeofday(&te, NULL);
long long milliseconds = te.tv_sec*1000LL + te.tv_usec/1000;
printf("[Time Sent: %lld]", milliseconds);
printf("[msg size = %d size = %d]\n", nbytes, size);
//added
pthread_create( &sendT, NULL, recvMessage, (void*) addrlen);
//size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&target_pc,&addrlen);
printf("Echo message: ");
if((size > 0) && (size < 99))
{
buffer[size] = '\0'; //add the null byte so buffer now holds a string
i = puts((char *) buffer); // write this string to the display
}
//time
gettimeofday(&te2, NULL); // get current time
milliseconds = te.tv_sec*1000LL + te.tv_usec/1000; // caculate milliseconds
printf("[Time Received: %lld]\n", milliseconds);
pthread_join(sendT,NULL);
pthread_join(recvT,NULL);
}
#ifdef WIN
system("PAUSE");
#endif
return 0;
}
void *sendMessage( void *ptr ){
//size = sendto(sock, (char *) buffer, nbytes,flags,(struct sockaddr *)&target_pc,(int)ptr);
}
void *recvMessage( void *ptr ){
//size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&target_pc,(int*)ptr);
}
Here is udpserver.c for reference:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#ifdef WIN
#include <winsock.h>
#include <windows.h>
#endif
#ifndef WIN
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
#define PORT 20009
/* simple upd server
this program receives short messages (<99 characters) from any IP address
and writes them to the display
be sure to use the linker line option "-l wsock32"
*/
int main()
{
/* first define a socket
a socket is an I/O port like a file descriptor
*/
#ifdef WIN
SOCKET sock; /* SOCKET is a typedef for a structure */
#else
int sock;
#endif
int size;
int nbytes, flags;
#ifdef WIN
int addrlen;
#else
socklen_t addrlen;
#endif
int i;
/* char loopback[20]="127.0.0.1"; */
#ifdef WIN
WSADATA wsaData; /* This is struct holds Windows required data */
int nCode;
#endif
char buffer[100];
struct sockaddr_in server; /* this holds my IP address and port info */
struct sockaddr_in from; /* this holds the same info for the sender of the packet
I received */
/* the call to WSAStartup is Windows magic */
#ifdef WIN
if((nCode = WSAStartup(MAKEWORD(1,1), &wsaData)) != 0){
printf("Opps! WSA error %d\n",nCode);
exit;
}
#endif
/* create a socket called sock. It is a datagram socket */
sock = socket(AF_INET,SOCK_DGRAM,0);
if(sock < 0){
printf("socket error = %d\n", sock);
return -1;
}
server.sin_family = AF_INET; /* initialize the server address family */
server.sin_addr.s_addr = htonl(INADDR_ANY); /* notice this struct within a struct */
/* printf("%x\n",server.sin_addr.s_addr); */
server.sin_port = htons(PORT);
/* associate the socket with the address structure - this is called binding */
i = bind(sock, (struct sockaddr *) &server, sizeof(server));
if( i < 0) {
printf("bind result: %d\n", i);
return -1;
} else
printf("Simple UDP server is ready!\n\n");
nbytes = 99; /* receive packets up to 99 bytes long */
flags = 0; /* must be zero or this will not work! */
while(1){
/* the recvfrom function is a read and the arguments are:
sock - the socket we are reading
buffer - array into which to read the data
nbytes - read up to this many bytes
flags - used for special purposes - not needed here
from - sockaddr struct to hold the IP address and port of the sender of the packet
addrlen - the size of the sockaddr struct written by this function
*/
addrlen = sizeof(from);
size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&from, &addrlen);
if((size > 0) && (size < 99)){
buffer[size] = '\0'; /* add the null byte so buffer now holds a string */
i = puts((char *) buffer); /* write this string to the display */
}
//echo message back to client
if(sock < 0) {//
printf("socket error = %d\n", sock);//
return -1;//
}//
sendto(sock, buffer, nbytes, flags, (struct sockaddr *)&from,addrlen); //
}
#ifdef WIN
system("PAUSE");
#endif
return 0;
}
Ithink i found the problem. Im not sure, im typing and reading on a iPad.
In the end of your main function, you have placed the declaration of
void *sendMessage( void *ptr )
void *recvMessage( void *ptr )
inside of the main. Move them outside.
/tmp/cciYoHsc.o:udpclient.c:(.text+0x253): undefined reference to `_sendMessage'
/tmp/cciYoHsc.o:udpclient.c:(.text+0x2f2): undefined reference to `_recvMessage'
collect2: ld returned 1 exit status
I believe that this will solve the problem.
As i said, im not able to test the code myself.
Good luck
void *sendMessage( void *ptr ){
size = sendto(sock, (char *) buffer, nbytes,flags,(struct sockaddr *)&target_pc,(int)ptr);
}
void *recvMessage( void *ptr ){
size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&target_pc,(int*)ptr);
}
you define size in main then try and use it in your threaded functions, you cant do that...

Resources