Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

C++ help :-)

Options
  • 19-01-2008 5:01pm
    #1
    Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,086 Mod ✭✭✭✭


    Hi, I need to use sockets and UDP, so I am trying to learn how to.

    I have gotten this example and am trying to get it running.
    http://www.codeproject.com/KB/IP/udptime.aspx

    I just created two projects and tried to run the source files. Before starting the client program, the server program has to be running. When I try to run this code:
    /* timeserv.c */
    /* A simple UDP server that sends the current date and time to the client */
    /* Last modified: September 20, 2005 */
    /* http://www.gomorgan89.com */
    /* Link with library file wsock32.lib */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <winsock.h>
    #include <time.h>
    
    #define BUFFER_SIZE 4096
    
    void usage(void);
    
    
    int main(int argc, char **argv)
    {
    	WSADATA w;							/* Used to open windows connection */
    	unsigned short port_number;			/* Port number to use */
    	int a1, a2, a3, a4;					/* Components of address in xxx.xxx.xxx.xxx form */
    	int client_length;					/* Length of client struct */
    	int bytes_received;					/* Bytes received from client */
    	SOCKET sd;							/* Socket descriptor of server */
    	struct sockaddr_in server;			/* Information about the server */
    	struct sockaddr_in client;			/* Information about the client */
    	char buffer[BUFFER_SIZE];			/* Where to store received data */
    	struct hostent *hp;					/* Information about this computer */
    	char host_name[256];				/* Name of the server */
    	time_t current_time;				/* Current time */
    
    	/* Interpret command line */
    	if (argc == 2)
    	{
    		/* Use local address */
    		if (sscanf(argv[1], "%u", &port_number) != 1)
    		{
    			usage();
    		}
    	}
    	else if (argc == 3)
    	{
    		/* Copy address */
    		if (sscanf(argv[1], "%d.%d.%d.%d", &a1, &a2, &a3, &a4) != 4)
    		{
    			usage();
    		}
    		if (sscanf(argv[2], "%u", &port_number) != 1)
    		{
    			usage();
    		}
    	}
    	else
    	{
    		usage();
    	}
    
    	/* Open windows connection */
    	if (WSAStartup(0x0101, &w) != 0)
    	{
    		fprintf(stderr, "Could not open Windows connection.\n");
    		exit(0);
    	}
    
    	/* Open a datagram socket */
    	sd = socket(AF_INET, SOCK_DGRAM, 0);
    	if (sd == INVALID_SOCKET)
    	{
    		fprintf(stderr, "Could not create socket.\n");
    		WSACleanup();
    		exit(0);
    	}
    
    	/* Clear out server struct */
    	memset((void *)&server, '\0', sizeof(struct sockaddr_in));
    
    	/* Set family and port */
    	server.sin_family = AF_INET;
    	server.sin_port = htons(port_number);
    
    	/* Set address automatically if desired */
    	if (argc == 2)
    	{
    		/* Get host name of this computer */
    		gethostname(host_name, sizeof(host_name));
    		hp = gethostbyname(host_name);
    
    		/* Check for NULL pointer */
    		if (hp == NULL)
    		{
    			fprintf(stderr, "Could not get host name.\n");
    			closesocket(sd);
    			WSACleanup();
    			exit(0);
    		}
    		
    		/* Assign the address */
    		server.sin_addr.S_un.S_un_b.s_b1 = hp->h_addr_list[0][0];
    		server.sin_addr.S_un.S_un_b.s_b2 = hp->h_addr_list[0][1];
    		server.sin_addr.S_un.S_un_b.s_b3 = hp->h_addr_list[0][2];
    		server.sin_addr.S_un.S_un_b.s_b4 = hp->h_addr_list[0][3];
    	}
    	/* Otherwise assign it manually */
    	else
    	{
    		server.sin_addr.S_un.S_un_b.s_b1 = (unsigned char)a1;
    		server.sin_addr.S_un.S_un_b.s_b2 = (unsigned char)a2;
    		server.sin_addr.S_un.S_un_b.s_b3 = (unsigned char)a3;
    		server.sin_addr.S_un.S_un_b.s_b4 = (unsigned char)a4;
    	}
    
    	/* Bind address to socket */
    	if (bind(sd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1)
    	{
    		fprintf(stderr, "Could not bind name to socket.\n");
    		closesocket(sd);
    		WSACleanup();
    		exit(0);
    	}
    
    	/* Print out server information */
    	printf("Server running on %u.%u.%u.%u\n", (unsigned char)server.sin_addr.S_un.S_un_b.s_b1,
    											  (unsigned char)server.sin_addr.S_un.S_un_b.s_b2,
    											  (unsigned char)server.sin_addr.S_un.S_un_b.s_b3,
    											  (unsigned char)server.sin_addr.S_un.S_un_b.s_b4);
    	printf("Press CTRL + C to quit\n");
    
    	/* Loop and get data from clients */
    	while (1)
    	{
    		client_length = (int)sizeof(struct sockaddr_in);
    
    		/* Receive bytes from client */
    		bytes_received = recvfrom(sd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client, &client_length);
    		if (bytes_received < 0)
    		{
    			fprintf(stderr, "Could not receive datagram.\n");
    			closesocket(sd);
    			WSACleanup();
    			exit(0);
    		}
    
    		/* Check for time request */
    		if (strcmp(buffer, "GET TIME\r\n") == 0)
    		{
    			/* Get current time */
    			current_time = time(NULL);
    			
    			/* Send data back */
    			if (sendto(sd, (char *)&current_time, (int)sizeof(current_time), 0, (struct sockaddr *)&client, client_length) != (int)sizeof(current_time))
    			{
    				fprintf(stderr, "Error sending datagram.\n");
    				closesocket(sd);
    				WSACleanup();
    				exit(0);
    			}
    		}
    	}
    	closesocket(sd);
    	WSACleanup();
    
    	return 0;
    }
    
    void usage(void)
    {
    	fprintf(stderr, "timeserv [server_address] port\n");
    	exit(0);
    }
    


    I get these errors:

    Linking...
    timeserv.obj : error LNK2001: unresolved external symbol "int __stdcall sendto(unsigned int,char const *,int,int,struct sockaddr const *,int)" (?sendto@@$$J224YGHIPBDHHPBUsockaddr@@H@Z)
    timeserv.obj : error LNK2001: unresolved external symbol "int __stdcall recvfrom(unsigned int,char *,int,int,struct sockaddr *,int *)" (?recvfrom@@$$J224YGHIPADHHPAUsockaddr@@PAH@Z)
    timeserv.obj : error LNK2001: unresolved external symbol "int __stdcall bind(unsigned int,struct sockaddr const *,int)" (?bind@@$$J212YGHIPBUsockaddr@@H@Z)
    timeserv.obj : error LNK2001: unresolved external symbol "int __stdcall closesocket(unsigned int)" (?closesocket@@$$J14YGHI@Z)
    timeserv.obj : error LNK2001: unresolved external symbol "struct hostent * __stdcall gethostbyname(char const *)" (?gethostbyname@@$$J14YGPAUhostent@@PBD@Z)
    timeserv.obj : error LNK2001: unresolved external symbol "int __stdcall gethostname(char *,int)" (?gethostname@@$$J18YGHPADH@Z)
    timeserv.obj : error LNK2001: unresolved external symbol "unsigned short __stdcall htons(unsigned short)" (?htons@@$$J14YGGG@Z)
    timeserv.obj : error LNK2001: unresolved external symbol "int __stdcall WSACleanup(void)" (?WSACleanup@@$$J10YGHXZ)
    timeserv.obj : error LNK2001: unresolved external symbol "unsigned int __stdcall socket(int,int,int)" (?socket@@$$J212YGIHHH@Z)
    timeserv.obj : error LNK2001: unresolved external symbol "int __stdcall WSAStartup(unsigned short,struct WSAData *)" (?WSAStartup@@Z)
    C:\Documents and Settings\Paul\My Documents\Visual Studio Projects\server\Debug\server.exe : fatal error LNK1120: 10 unresolved externals

    Build log was saved at "file://c:\Documents and Settings\Paul\My Documents\Visual Studio Projects\server\Debug\BuildLog.htm"
    server - 11 error(s), 0 warning(s)


    Done

    Build: 0 succeeded, 1 failed, 0 skipped
    Anybody know what is wrong?

    Cheers.


Comments

  • Closed Accounts Posts: 2,349 ✭✭✭nobodythere


    under the #includes put:

    #pragma comment(lib,"ws2_32.lib");


  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,086 Mod ✭✭✭✭Tar.Aldarion


    Thanks mate, now both server and client compile and a console appears for both, I can't type in them though. I thought you were meant to type 'timecli ip port' in the console one?
    Or do I edit the program?


  • Registered Users Posts: 981 ✭✭✭fasty


    I haven't really looked at the code, but perhaps the IP and Port are command line parameters?


  • Closed Accounts Posts: 413 ✭✭sobriquet


    Thanks mate, now both server and client compile and a console appears for both, I can't type in them though. I thought you were meant to type 'timecli ip port' in the console one?
    Or do I edit the program?

    It looks like - the code you posted does try to parse the args for at least a port number and optionally an ip address. If it's running them as console apps, it's probably tried to execute them - it should print the usage() string, does it?

    To get VS to launch the built exe with args, you'll need to edit your build properties to append them to it when it tries to run it. It's the server, so just append on 8080 as a port (above 1024 or else you'll need to run as root - does that apply on windows?).

    For the client code, you probably need to append the loopback addr to them, 127.0.0.1 and the port you're running the server on (8080).

    I forget where the build properties options are in VS, shouldn't be too hard to find. Hope that helps.

    If you need to learn sockets, a good bet is Beejs guide to network programming. It's in C, but that shouldn't matter too much for your purposes. Might be easier to understand than the source you have there.


  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,086 Mod ✭✭✭✭Tar.Aldarion


    Thanks for the post.
    I'll try to get it working.
    I'm also trying a new example.
    http://www.tenouk.com/Winsock/Winsock2example9.html


    I'm just trying to learn this stuff because I have a program with the functionality to "parse" the strings being received from a different program is order to identify the string which contains a serial number and then extract this serial number.

    I now need the functionality to open a UDP port then to form a UDP segment in some format defined by myself that contains the relevant information i.e. area, serial number, owner name etc. I then need to send this packet out over the UDP port.

    The next phase will be development of another program which will receive this packet, extract the relevant information and update the MySQL database.


    The search goes on.


  • Advertisement
  • Registered Users Posts: 26,558 ✭✭✭✭Creamy Goodness


    might be related to your problem but if you are reading the port number in from the command line it will be coming in as a char and not a integer.

    using the atoi() function will solve this.


  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,086 Mod ✭✭✭✭Tar.Aldarion


    Thanks everybody, I have a few examples working now.
    In my main one I send sometext to the server, I now have to change that so that it sends the contents of a text file over and over as the contents of the text file will be changing.
    Then the server has to recognise all these, especially the changes in input to it and upload it to a MySQL database.
    Hmm..


  • Closed Accounts Posts: 413 ✭✭sobriquet


    Hmm..

    Sounds fairly straightforward. If you're only using a single socket on the server you should be able to use blocking sockets without trouble. Your client will have a main loop that amounts to parsefile() -> sendto() -> sleep(n). Your server will have a similar one that instead of sleep()ing, blocks on the socket it's listening on, and when it receives data it processes it, uploading the data to the MySQL server.

    If you're sending variable length data, be sure to prefix the data with the length, and I'd stick in a version byte too, in case you want to be able handle things differently for different types of data.


  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,086 Mod ✭✭✭✭Tar.Aldarion


    Thanks sobriquet.

    Is it easy to stop it uploading information it has uploaded before?

    Actually, I was thinking of putting all the data in the database manually and having a boolean field so that when the data is recieved, only that data entry should be dealt with, not uploaded though. I will be recieving serial numbers. That value/serial number would be the one that was 'true' and the rest would be 'false'. Is that easy peasy? :)


  • Closed Accounts Posts: 413 ✭✭sobriquet


    I'm not sure I'm following you tbh. What exactly is the program intended to do?

    Do you have the list of serials to start with? If so, then yes I'd say preconfiguring your database is a better idea. If you can do that, it allows you do the 'hard' work in MySQL, and keep your C++ code as dumb as it can be, which is preferable in my mind. The less lines of C/C++ in the world the better.

    It'd be easy enough. If you go this route, I'd recommend having a Timestamp column as well. Whenever you set the active row, set this column to CURRENT_TIMESTAMP (that's the ANSI SQL version, MySQL should have it but if not they'll have something like it). It'll be a fallback for when two rows have the active bool set, the most recent is probably the right one.

    Alternately, for a more normalized solution, you could have Serials table, and an ActiveSerial table that will only have one row in it. Your proc would verify that the serial passed in to you exists in Serials, then set the ActiveSerial row to that value. I'd still have a timestamp column in the Serials table for a historical record.

    If the table is big, you can put an index on the serials column for your select statement.


  • Advertisement
  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,086 Mod ✭✭✭✭Tar.Aldarion


    Yup I have all the serial numbers.
    As for what the program does:
    They are read in from cards via an RFID reader. The current one is written to a file, this then has to be sent over UDP to another computer etc, as we have discussed. The database has to know what serial number is active and then I know which serial number I have to deal with.
    I then have to reroute Istant messages based on what serial number I have detected.


    I could usea timestamp yes, or just have it so that when one is true the rest are set to false, I take it.
    Cheers.


  • Closed Accounts Posts: 413 ✭✭sobriquet


    I could usea timestamp yes, or just have it so that when one is true the rest are set to false, I take it.
    Actually I meant that you do both. Use the bool field for your active record, and the timestamp as a safety measure, for if (when) two rows get set to true.


  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,086 Mod ✭✭✭✭Tar.Aldarion


    Ah, yep, coolaboola.


Advertisement