Alright, so, I decided to write an IRC Bot in C++ to get used to socket programming. Everything went fine of course, but I have one bug: when the server sends me a PRIVMSG (a message sent by a user to the server, then comes to me) it prints a total of 512 characters, the size of my buffer, not just the privmsg. (which it needs to be)

anyways, here is the code, and all tips are welcome.

socket.cpp

/*
* Author: Fellixombc
* Copyright (c) 2010
* socket.cpp
* @Connects to IRC Server's Socket
*/
#include "socket.h"

void Socket::Connect(char* server, int port) {
	
	/* Intilize WSA */
	version = MAKEWORD(2, 2); // Version
	error = WSAStartup(version, &wsaData);
	cout << "Starting up WSA..." << endl;

	/* Create Socket */
	client = socket( AF_INET, SOCK_STREAM, 0 );  //create socket
	/* Fail Safe for Socket Creation */
		if (client == INVALID_SOCKET) {
			cout << "INVALID SOCKET" << endl;
			WSACleanup();
			system("puase");
		}
	cout << "Creating socket..." << endl;
	
	/* Socket Settings */
	struct hostent *host; // Set a pointer to the struct!
	host = gethostbyname(server); // Set the host...
	SOCKADDR_IN SockAddr; // Create socket
	SockAddr.sin_port=htons(port); // Port
	SockAddr.sin_family=AF_INET; // Connection Family
	SockAddr.sin_addr.s_addr=*((unsigned long*)host->h_addr); // Simply getting the host address that we inputted earlier!
	cout << "Set socket varibles..." << endl;
	
	
	/* Connect to Socket */
	connect(client, (SOCKADDR*)(&SockAddr), sizeof(SockAddr));
	cout << "Socket connected!" << endl;
}

void Socket::Disconnect() {

	/* Close Socket */
	closesocket(client);
	cout << "Closing socket..." << endl;

	/* Clean(destroy) WSA */ 
	WSACleanup();
	cout << "Cleaning up WSA..." << endl;	
	system("pause");

}

void Socket::Send(string input) {
	
	/* Length of Text being sent	*/
		int inputLength = input.length();
	
	/* Send the socket the text */
	sendToServer = send(client, input.c_str(), inputLength, 0); //(Send Source, Text, Length of text, 0)
	
	/* Tell us what we sent! */
	cout << "Sent: " << input;
}

string Socket::Recv() {
	
	int i = 0;
	Bot *bot = new Bot();
	
	do {
		int dataLen = recv(client, recvBuffer, 1024, 0);
		buffer = recvBuffer; 
		
		int lastChar = buffer.find_last_of("\n");
		buffer.erase(lastChar);
		
		if (dataLen > 0) {
			if (buffer.find("PING ") != std::string::npos)
				{
					i++;
					if (inChannel = false)
						{
							Send("PONG :" + buffer.substr((buffer.find_last_of(":")+1), (buffer.find_last_of("\r")-1)) + "\n");
							Send("JOIN #bots\r\n");	
						}
						else
						{
							Send("PONG :" + buffer.substr((buffer.find_last_of(":")+1), (buffer.find_last_of("\r")-1)) + "\n");	
						}

				}
			if (buffer.find("PRIVMSG #bots :12345"))
				{
				cout << endl << dataLen + "- !!!FOUND LINE!!! -" << endl << buffer << endl;
				}
				else
				{
				cout << endl << dataLen << endl << buffer << endl;	
				}
		} else if (dataLen == 0) {
			printf("connection closed");
			system("pause");
			Socket::Disconnect();
		} else {
			printf("Error: %d", WSAGetLastError());
			system("pause");
			Socket::Disconnect();
		}
	} while (dataLen > 0);
}

socket.h:

#include <windows.h> 
#include <stdlib.h> 
#include <stdio.h>  
#include <winsock2.h> 

using namespace std;

class Socket {
protected:
	/* Socket Data */
	WSADATA wsaData;
	WORD version;
	SOCKET client;
	struct hostent *host;
	SOCKADDR_IN SockAddr;
	
	/* Other */
	int error;
	int sendToServer;
	int inputLength;
	char recvBuffer[1024];
	string buffer;
	int dataLen;
public:
	void Connect(char*, int);
	void Disconnect();
	void Send(string);
	string Recv();
	bool inChannel;
};

Edited 6 Years Ago by fellixombc: n/a

> int dataLen = recv(client, recvBuffer, 1024, 0);
You're assuming several things (all of which are false, eventually)

1. That for every "message" sent, you get "message". STREAM sockets can fragment the message (only the byte order is guaranteed). So you might get "mess" or even "messagemessageme".

2. That every message has a \0 (to make it a proper string). If you don't send one, then there isn't one added automatically.
Typically, this means using sizeof(buff)-1 in the recv call to allow for easy appending of a \0 if you need to.

3. Use the length before doing anything else with the message.
len = recv....
if ( len > 0 ) buff[len] = '\0';

Then you can treat buff as a proper c-string.

Comments
Good ol' fashioned advice, full of that ying yang goodness.

> int dataLen = recv(client, recvBuffer, 1024, 0);
You're assuming several things (all of which are false, eventually)

1. That for every "message" sent, you get "message". STREAM sockets can fragment the message (only the byte order is guaranteed). So you might get "mess" or even "messagemessageme".

2. That every message has a \0 (to make it a proper string). If you don't send one, then there isn't one added automatically.
Typically, this means using sizeof(buff)-1 in the recv call to allow for easy appending of a \0 if you need to.

3. Use the length before doing anything else with the message.
len = recv....
if ( len > 0 ) buff[len] = '\0';

Then you can treat buff as a proper c-string.

So get the length of the message being recv'd, and then add \0 to the message to treat it properly as a string, correct?

Ok I figured it out, a friend helped me.

I just get the amount the socket is sending me, plug it into my recv function, print it with \0 added to a char that is the size of information being sent +1 (for \0)


Thanks for the help though! This can be locked.

This article has been dead for over six months. Start a new discussion instead.