Personal tools
Document Actions

lesson7.cpp

by aullmj — last modified 2009-01-26 17:58

basic network communication don't look for a pdf, all info is in comments in file.

Click here to get the file

Size 4.7 kB - File type text/x-c++src

File contents

//Simple user-hostile instant messaging program
//Mark Aull, 2009
//wsock32.lib must be linked with this program.
#include <stdio.h>
#include "winsock.h"

//A thread is needed for the program to listen for 
//incoming messages while being able to send them
//at the user's request.
HANDLE hThread;
long WINAPI RecvThread(double lParam[]);

void main(void)
{//begin main
	WSADATA wsData;
	DWORD dwID;
	SOCKET RecvSock,SendSock;//local sockets
	SOCKADDR_IN RecvAddr,SendAddr, RemoteAddr;//addresses
	double data[5];
	char szHostName[256],*szLocalIP,msg[256];
	memset(msg,0,256*sizeof(char));
	strcpy(msg,"thread started");
	printf("World's least user friendly IM program\nby Mark Aull\n");
	printf("Instructions: type an IP address, press enter.\nType a message, press enter.\nPress Enter twice to exit.\n\n");

	//Start winsock, Get the local hostname and IP address
	WSAStartup(MAKEWORD(2,2),&wsData);
	gethostname(szHostName, 255);
	printf("on host: %s\n",szHostName);
	struct hostent *host_entry;
	host_entry=gethostbyname(szHostName);
	szLocalIP = inet_ntoa (*(struct in_addr *)host_entry->h_addr_list[0]);//note: change to h_addr_list[1] for wireless
	printf("on IP: %s\n",szLocalIP);

//bind to port on local for recieving stuff
	memset(&RecvAddr, 0, sizeof(SOCKADDR_IN));
	//make address corresponding to desired port on this computer
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(3795);//port we're listening to
	RecvAddr.sin_addr.s_addr=inet_addr(szLocalIP);
	//make socket, bind to address created above
	RecvSock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
	int iErr=bind(RecvSock,(LPSOCKADDR)&RecvAddr,sizeof(SOCKADDR));
	iErr=WSAGetLastError();

//bind to port on local for sending stuff
	memset(&SendAddr, 0, sizeof(SOCKADDR_IN));
	//make address corresponding to desired port on this computer
    SendAddr.sin_family = AF_INET;
    SendAddr.sin_port = htons(3794);//port we're sending from
	SendAddr.sin_addr.s_addr=inet_addr(szLocalIP);
	//make socket, bind to address created above
	SendSock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
	iErr=bind(SendSock,(LPSOCKADDR)&SendAddr,sizeof(SOCKADDR));
	iErr=WSAGetLastError();

	//run receiving stuff in another thread
	data[0]=1;//this variable is used to terminate the thread from this function.
	//the memory location of the recieving socket is converted to an integer
	//and stored into the memory location at &data[1], which is treated as an integer.
	*((int*)&data[1])=int(&RecvSock);
	hThread= CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RecvThread,LPVOID(&data[0]),0,&dwID);//start receive thread

	sendto(SendSock,msg,256,MSG_DONTROUTE,(LPSOCKADDR)&RecvAddr,sizeof(SOCKADDR));//send test message to self
	while (msg[0]!=0)
	{//runs until user inputs a blank message
		gets_s(msg,256);//get line from keyboard containing an IP address
		RemoteAddr.sin_addr.s_addr=inet_addr(msg);//use it to make a destination address
		RemoteAddr.sin_family = AF_INET;
		RemoteAddr.sin_port = htons(3795);//on the same port we're listening to

		gets_s(msg,256);//get line from keyboard containing message
		sendto(SendSock,msg,256,MSG_DONTROUTE,(LPSOCKADDR)&RemoteAddr,sizeof(SOCKADDR));//send message to IP address as commanded
	}
	data[0]=0;//send stop command to thread
	strcpy(msg,"stop thread");//send message because otherwise it hangs on recvfrom because
	sendto(SendSock,msg,256,MSG_DONTROUTE,(LPSOCKADDR)&RecvAddr,sizeof(SOCKADDR));//recvfrom is a blocking function.
	WaitForSingleObject(hThread, 1000);//wait for thread to stop
	CloseHandle(hThread);//kill thread
	closesocket(RecvSock);// close socket
	closesocket(SendSock);// close socket
}
typedef unsigned char uc;
long WINAPI RecvThread(double lParam[])
{//recieving stuff thread
	sockaddr FromAddr;//address will be set to whatever address we get stuff from.
	int len=sizeof(FromAddr),ii;//recvfrom needs a pointer to this length for some stupid reason.
	//The memory location of the recieving socket which was stored as an integer
	//is pulled out of the double array it was stored in, and used as the memory location
	//for a pointer to a socket, which is what it was originally.
	SOCKET *RSock=(SOCKET*)*(int*)&lParam[1];
	char msg[256];//character buffer

	while (lParam[0]>0)
	{//run until someone sets data[0] (lParam[0]) to 0
		memset(msg,0,256*sizeof(char));//clear buffer in preparation for message.
		ii=recvfrom(*RSock,msg,256,0,&FromAddr,&len);//wait here until someone sends a message
		if (ii<0)//if there's an error, 
			ii=WSAGetLastError();//get an error code
		//otherwise display who sent what
		printf("received %d bytes from %d.%d.%d.%d: %s\n",ii,uc(FromAddr.sa_data[2]),
			uc(FromAddr.sa_data[3]),uc(FromAddr.sa_data[4]),uc(FromAddr.sa_data[5]),msg);
	}
	return 0;
}