// by Sabrina Rispin // Activity Section: 5 & 6 // Date: 13/4/15 - 24/4/15 // Description: determines how many steps it takes for a point on the // complex plane c to escape the funciton z^2 + c upon iteration. #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <string.h> #include <netinet/in.h> #include <unistd.h> #include <math.h> #include "mandelbrot.h" #include "pixelColor.h" // server defines #define SIMPLE_SERVER_VERSION 2.0 #define REQUEST_BUFFER_SIZE 100 #define DEFAULT_PORT 7191 #define NUMBER_OF_PAGES_TO_SERVE 100 // after serving this many pages the server will halt // defines for escapeSteps, serveBMP and extract #define TRUE 1 #define FALSE 0 #define MAX_ITER 256 #define SIZE 512 // ie the width of the image (also the height) #define POWER 2.0 // step = 2^-zoom #define ESCAPE_DISTANCE 4 #define SIZE_OF_HEADER 54 #define BYTES_PER_PIXEL 10 #define SIZE_OF_BMP (SIZE * SIZE * BYTES_PER_PIXEL) #define MAX_LEN_INPUT 50 #define OFFSET 2 #define COLOR_MODE 'R' // bits8 for serveBMP and triordinate for extract typedef unsigned char bits8; typedef struct _triordinate { double x; double y; int z; } triordinate; static void serveHTML (int socket); static void serveBMP (int socket, double x, double y, int zoom); static triordinate extract (char *message); static int waitForConnection (int serverSocket); static int makeServerSocket (int portno); int main (int argc, char* argv[]) { // sets up the server printf ("************************************\n"); printf ("Starting simple server %f\n", SIMPLE_SERVER_VERSION); printf ("Serving mandelbrots since 2012\n"); printf ("Access server at http://localhost:%d/\n", DEFAULT_PORT); printf ("************************************\n"); int serverSocket = makeServerSocket(DEFAULT_PORT); char request[REQUEST_BUFFER_SIZE]; int numberServed = 0; while (numberServed < NUMBER_OF_PAGES_TO_SERVE) { printf ("*** So far served %d pages ***\n", numberServed); // STEP 1. wait for a request to be sent from a web browser, // then open a new connection for this conversation int connectionSocket = waitForConnection(serverSocket); // STEP 2. read the first line of the request int bytesRead = recv (connectionSocket, request, sizeof(request) - 1, 0); assert (bytesRead >= 0); // check that we were able to read some data from the connection // echo entire request to the console for debugging printf (" *** Received http request ***\n %s\n", request); // Finds the start and end of the shorter, more useful request // from the url. Also checks there is an x, y and z. int startReq = 0; int endReq = 0; int valuesPresent = 0; while (request[endReq] != 'H') { if (request[endReq] == '/') { startReq = endReq; } if (request[endReq] == 'x' || request[endReq] == 'y' || request[endReq] == 'z') { valuesPresent += 1; } endReq++; } // Gotta terminate that new string! request[endReq] = '\0'; char *shortRequest = &request[startReq]; printf("URL Short Request: %s\n", shortRequest); // STEP 3. send the browser stuff printf (" *** Sending http response ***\n"); // If x y and z serve BMP, else serve html interactive version if (valuesPresent == 3) { triordinate input = extract (shortRequest); serveBMP (connectionSocket, input.x, input.y, input.z); } else { printf ("HTML TIME\n"); serveHTML (connectionSocket); } // STEP 4. close the connection after sending the page- // keep aust beautiful close (connectionSocket); ++numberServed; } // close the server connection after we are done-keep aust beautiful printf ("** shutting down the server **\n"); close (serverSocket); return EXIT_SUCCESS; } // mandelbrot functions int escapeSteps (double x, double y) { int escaped = FALSE; double zRe = 0.0; double zIm = 0.0; // need the below in order to simultaneously update double newRe = 0.0; double newIm = 0.0; //printf ("Real c: %lf, Imaginary c: %lf\n", x, y); // The calcs! int iter = 0; while ((iter < MAX_ITER) && (escaped != TRUE)) { iter++; newRe = zRe * zRe - zIm * zIm + x; newIm = 2 * zRe * zIm + y; zRe = newRe; zIm = newIm; if (zRe*zRe + zIm*zIm >= ESCAPE_DISTANCE) { escaped = TRUE; } } //printf ("%d\n", iter); return iter; } // server functions static void serveHTML (int socket) { char *message; // first send the http response header message = "HTTP/1.0 200 Found\n" "Content-Type: text/html\n" "\n"; printf ("about to send=> %s\n", message); write (socket, message, strlen (message)); // serves the html script for the interactive mandelbrot message = "<!DOCTYPE html>\n" "<script src=\"https://almondbread.cse.unsw.edu.au/tiles.js\"></script>" "\n"; write (socket, message, strlen (message)); } static void serveBMP (int socket, double x, double y, int zoom) { char *message; // first send the http response header message = "HTTP/1.0 200 OK\r\n" "Content-Type: image/bmp\r\n" "\r\n"; printf ("about to send=> %s\n", message); write (socket, message, strlen (message)); // serve the BMP header bits8 header[SIZE_OF_HEADER] = { 0x42, 0x4D, 0x36, 0x00, // 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; write (socket, header, sizeof (header)); // all the things and counters needed double step = pow (POWER, -zoom); double xStart = -step*SIZE/2 + step/2 + x; double xPos = xStart; double yPos = -step*SIZE/2 + step/2 + y; int xCount = 0; int yCount = 0; int arrayPos = 0; int iter; // the bmp array! bits8 bmp[SIZE_OF_BMP]; while (yCount < SIZE) { while (xCount < SIZE) { // calcs number of iters to blow up then uses that to color iter = escapeSteps (xPos, yPos); bits8 blue; bits8 red; bits8 green; if (COLOR_MODE == 'B') { blue = stepsToRed (iter); red = stepsToGreen (iter); green = stepsToBlue (iter); } else if (COLOR_MODE == 'G') { green = stepsToRed (iter); blue = stepsToGreen (iter); red = stepsToBlue (iter); } else { red = stepsToRed (iter); green = stepsToGreen (iter); blue = stepsToBlue (iter); } // add the pixel bmp[arrayPos] = blue; arrayPos++; bmp[arrayPos] = green; arrayPos++; bmp[arrayPos] = red; arrayPos++; // to the next pixel! (Also keeps track of how many pixels) xPos += step; xCount++; } // at the end of a row reset xPos, add a step to yPos and inc y xPos = xStart; yPos += step; yCount++; xCount = 0; } write (socket, bmp, sizeof (bmp)); } // extracting x y z function triordinate extract (char *message) { // incase the values after x y and z are empty, set initial vals triordinate tri = {0, 0, 7}; // set start pos at extereme end // (not 0, if no update then start will include the whole string!) int xStart = strlen (message); int yStart = strlen (message); int zStart = strlen (message); int zEnd = strlen (message) - 1; // the final x, y and z as strings to go into ato_ char x[MAX_LEN_INPUT]; char y[MAX_LEN_INPUT]; char z[MAX_LEN_INPUT]; // clears the array by filling it wil escaped 0 memset (x, '\0', MAX_LEN_INPUT); memset (y, '\0', MAX_LEN_INPUT); memset (z, '\0', MAX_LEN_INPUT); // this loops looks for an _ the looks as the next char // if x y or z set correspoding Start value // OFFSET = 2 because _x0.4 hence start of num is i (pos of _) + 2 int i = 0; while (i < strlen (message)) { if (message[i] == '_') { if (message[i+1] == 'x') { xStart = i + OFFSET; } else if (message[i+1] == 'y') { yStart = i + OFFSET; } else if (message[i+1] == 'z') { zStart = i + OFFSET; } } // _z5.bmp so . is the end of z if (message[i] == '.') { zEnd = i; } i++; } // copies the specific string i.e. -0.4 (from _x-0.4) to x etc. // strncpy args: copyToString, copyFromString, length // note: yStart - xStart = length of _x-0.4 (-OFFSET for real len) strncpy (x, message + xStart, yStart - xStart - OFFSET); strncpy (y, message + yStart, zStart - yStart - OFFSET); strncpy (z, message + zStart, zEnd - zStart); //printf ("%s\n", x); //printf ("%s\n", y); //printf ("%s\n", z); // eg if _x_y0.5_z6 there is no x val, strlen (x) == 0, don't update if (strlen (x) > 0) { tri.x = atof (x); } if (strlen (y) > 0) { tri.y = atof (y); } if (strlen (z) > 0) { tri.z = atol (z); } return tri; } // start the server listening on the specified port number static int makeServerSocket (int portNumber) { // create socket int serverSocket = socket (AF_INET, SOCK_STREAM, 0); assert (serverSocket >= 0); // check there was no error in opening the socket // bind the socket to the listening port (7191 in this case) struct sockaddr_in serverAddress; serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = INADDR_ANY; serverAddress.sin_port = htons (portNumber); // tell the server to restart immediately after a previous shutdown // even if it looks like the socket is still in use // otherwise we might have to wait a little while before rerunning the // server once it has stopped const int optionValue = 1; setsockopt (serverSocket, SOL_SOCKET, SO_REUSEADDR, &optionValue, sizeof (int)); int bindSuccess = bind (serverSocket, (struct sockaddr*)&serverAddress, sizeof (serverAddress)); assert (bindSuccess >= 0); // if this assert fails wait a short while to let the operating // system clear the port before trying again return serverSocket; } // wait for a browser to request a connection, // returns the socket on which the conversation will take place static int waitForConnection (int serverSocket) { // listen for a connection const int serverMaxBacklog = 10; listen (serverSocket, serverMaxBacklog); // accept the connection struct sockaddr_in clientAddress; socklen_t clientLen = sizeof (clientAddress); int connectionSocket = accept (serverSocket, (struct sockaddr*)&clientAddress, &clientLen); assert (connectionSocket >= 0); // check for connection error return connectionSocket; }
Download file: mandelbrot.c
(11.4 KB)