Advertisement

problem with receiving

Started by June 17, 2002 03:11 PM
4 comments, last by evilclown 22 years, 7 months ago
(No matter what I do, code or source, it removes and double newlines, so it doesn't space between functions...) What am I doing wrong? It is supposed to recieve the code from google's main page

#include <iostream>
#include <winsock.h>
#include <cstdlib>
#include <string>
#include <vector>

SOCKET theSocket;

char *readLine();

char *readLine() {
   vector theVector;
   char buffer[1];
   while (true) {
      recv(theSocket, buffer, 1, 0);
      if (buffer[0] == '\n') {
         char * pChar = new char[theVector.size()];
         for (int f = 0; f < theVector.size(); f++) {
            pChar[f] = theVector[f];
	 }
         return pChar;
      } else {
         theVector.push_back(buffer[0]);
      }
   }
}

int main(int argc, char *argv[]){

  WORD version = MAKEWORD(1,1);
  WSADATA wsaData;
  int nRet;

  //start winsock
  WSAStartup(version, &wsaData);

  //store info about the server
  LPHOSTENT lpHostEntry;

  lpHostEntry = gethostbyname("www.google.com");
  if(lpHostEntry == NULL) {
    cerr << "Error at gethostbyname()" << endl;
    system("pause");
    return -1;
  }

  //create socket
  //over tcp/ip, socket type, protocal
  theSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  //SOCKADDR_IN to fill in address info
  SOCKADDR_IN saServer;

  saServer.sin_family = AF_INET;
  //address of server being inserted into addr field
  saServer.sin_addr = *((LPIN_ADDR)*lpHostEntry->h_addr_list);
  saServer.sin_port = htons(80);

  //connect
  //server addr, sizeof addr struct
  nRet = connect(theSocket, (LPSOCKADDR)&saServer, sizeof(struct sockaddr));

  if(nRet == SOCKET_ERROR) {
    cerr << "Error at connect()" << endl;
    system("pause");
    return -1;
  }

  //connected
  std::string strSend("get / HTTP/1.1\n\n");
  nRet = send(theSocket, strSend.c_str(), strSend.length(), 0);
  if(nRet == SOCKET_ERROR) {
    cerr << "Error at send()" << endl;
    system("pause");
    return -1;
  }

  //recieve
  cout << strSend.c_str() << endl << strSend.length() << endl;
  cout << readLine() << endl;

  closesocket(theSocket);

  //shutdown winsock
  WSACleanup();

  cout << "done." << endl;
  system("pause");
  return 0;
}
 
I think it is the send() line because it does not say there are any errors. I also tried sizeof(strSend.c_str()), but that didn't work either. [edited by - evilclown on June 17, 2002 4:15:06 PM] [edited by - evilclown on June 17, 2002 4:15:47 PM] [edited by - evilclown on June 17, 2002 4:16:26 PM] [edited by - evilclown on June 17, 2002 4:17:48 PM]
And why are windows/winsock structures named LP?
Advertisement
LP stands for Long (32-bit) Pointer. It meant something when 16-bit OS''s were around. Now that win95+ is 32-bit all pointers are long so it''s obsolete.
Standard debugging practise means you should really use a debugger and look at return values you think are suspect and to check the flow of your program.

Also why would you think doing a sizeof(strSend.c_str()) would help? sizeof returns the size of an element you pass to it while send expects a pointer. strSend.c_str() returns the pointer to the string.

There was one major bug, you were forgetting to null terminate the string you were passing back to cout which was producing rubbish. The second bug was that the response from the server is nto all on one line but as many lines separated by ''cr'' so you needed to use a loop to get all the lines and not just the first. The third bug was that you were not checking for recv() returning <= 0 indicating a graceful close or an error.

Here is your bug fixed code.


  #include <iostream.h>#include <winsock.h>#include <cstdlib>#include <string>#include <vector>SOCKET theSocket;char *readLine();// This function reads a line from the server// TODO : Optimise this to not use single byte recv''s however for this demonstration it is finechar *readLine(){	std::vector<char> theVector;	char buffer[1];	while (true)	{		int gotbytes = recv(theSocket, buffer, 1, 0);		// If we have no more data or there was an error then return with nothing		if (gotbytes <= 0)		{			return 0;			// Since we are using C++ ''0'' looks tidier than NULL		}		// We can assume that thye recv function having succeeded has put one char in to our buffer		// So test for a \n		if (buffer[0] == ''\n'')		// NOTE : Only works if \n equates to the same \n as the server. Luckily this does.		{			// +1 for null termination of the string			char * pChar = new char[theVector.size()+1];			// Remark : Using "for (int f = 0..." is not valid C++ if we expect to have int f valid after the scope of the cor statement			int f;			for (f = 0; f < theVector.size(); f++)			{				pChar[f] = theVector[f];			}			// Null terminate the string			pChar[f] = 0;		// NULL terminate our text line from Google			return pChar;		}		else		{			theVector.push_back(buffer[0]);		}	}}int main(int argc, char *argv[]){	WORD version = MAKEWORD(1,1);	WSADATA wsaData;	int nRet;	//start winsock	WSAStartup(version, &wsaData);	//store info about the server	LPHOSTENT lpHostEntry;	lpHostEntry = gethostbyname("www.google.com");	if(lpHostEntry == NULL)	{		cerr << "Error at gethostbyname()" << endl;		system("pause");		return -1;	}	//create socket	//over tcp/ip, socket type, protocal	theSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);	//SOCKADDR_IN to fill in address info	SOCKADDR_IN saServer;	saServer.sin_family = AF_INET;	//address of server being inserted into addr field	saServer.sin_addr = *((LPIN_ADDR)*lpHostEntry->h_addr_list);	saServer.sin_port = htons(80);	//connect	//server addr, sizeof addr struct	nRet = connect(theSocket, (LPSOCKADDR)&saServer, sizeof(struct sockaddr));	if(nRet == SOCKET_ERROR)	{		cerr << "Error at connect()" << endl;		system("pause");		return -1;	}	//connected	std::string strSend("get / HTTP/1.1\n\n");	nRet = send(theSocket, strSend.c_str(), strSend.length(), 0);	if(nRet == SOCKET_ERROR)	{		cerr << "Error at send()" << endl;		system("pause");		return -1;	}	//recieve	cout << strSend.c_str() << endl << strSend.length() << endl;	cout << "Getting data from server..." << endl;	char *linegot;	while ( (linegot = readLine()) != 0)	{		cout << linegot << endl;		// Remark : The line from readLine() is not freed, is this what you wanted?	}	closesocket(theSocket);	//shutdown winsock	WSACleanup();	cout << "done." << endl;	system("pause");	return 0;}  


Martin Piper
I don''t know how to debug. Thats why I was outputting all errors and exiting.

whats "Remark : The line from readLine() is not freed, is this what you wanted?" mean? Is it that the line is still taking up memory? I just wanted to output the line, but was following a tutorial.

I wanted to use sizeof because strSend.length() didn''t work, but thats because of the missing null terminator.

Why do I have to manually make a null terminator?

And lines like

nRet = connect(theSocket, (LPSOCKADDR)&saServer, sizeof(struct sockaddr));
if(nRet == SOCKET_ERROR) {

Should I be putting a WSACleanup()?
Yes you need a WSACleanup() in the end (or where you want)
it is used to undload ws_32.dll (wrong name?) that you loads with WSAStartup()
- Me

This topic is closed to new replies.

Advertisement