Created
January 23, 2016 07:44
-
-
Save LiamKarlMitchell/d3d5a2a50d82d5c7efa2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Sometimes when using Send and Recv API it will not send or recv all the data. You will notice your socket might have an error and gets disconnected. | |
// Such as the other end wont be able to recv the entire packet correctly or something. The bytes that were not sent are never sent. | |
// This is horrible of course, I did not read the fine print and just expected it to work -_- (okay I guess an error could happen half way through sending or receiving some data and thats why it works this way. | |
// Email: liamkarlmitchell@gmail.com | |
// License: MIT - do whatever you want with this code. | |
// Borrowed from UNIX Network Programming: Sockets Introduction | |
// By Andrew M. Rudoff, Bill Fenner, W. Richard Stevens Feb 27, 2004 | |
// http://www.informit.com/articles/article.aspx?p=169505&seqNum=9 | |
// Needed to modify it very slightly for nicety for Win32 and my "coding style". | |
// Note I have not cleaned up the code for the gist because im too tired and glad that it works. | |
// NOTE: Put your packet structures in this pragma pack push 1 it removes any of the byte padding the compiler adds. | |
// Like if I had the SomethingPacket_Init and set the id to 0 with a value of 0 it might send 8 bytes instead of 5 with the last 3 bytes of the char padded to 4 byte. | |
// Not ideal... Although maybe there are optimizations to be had in computation if you keep the structure aligned to 4 bytes? Heck knows. | |
#pragma pack(push, 1) | |
struct SomethingPacket { | |
unsigned char id; | |
}; | |
// PacketID: 0 | |
struct SomethingPacket_Init : SomethingPacket { | |
unsigned int value; | |
}; | |
#pragma pack(pop) | |
// Use this like you would send without the flags argument. | |
// It will keep sending if interupted. If there is an actuall error though it will return -1. | |
/* Write "n" bytes to a socket descriptor. */ | |
int writen(SOCKET sd, const void *vptr, unsigned int n) | |
{ | |
unsigned int nleft; | |
int nwritten; | |
const char *ptr; | |
ptr = (const char*)vptr; | |
nleft = n; | |
while (nleft > 0) { | |
if ( (nwritten = send(sd, ptr, nleft, 0)) <= 0) { | |
if (nwritten < 0 && errno == EINTR) { | |
nwritten = 0; /* and call write() again */ | |
} else { | |
return -1; /* error */ | |
} | |
} | |
nleft -= nwritten; | |
ptr += nwritten; | |
} | |
return n; | |
} | |
// Use this like you would use recv without the flags argument. | |
// It will keep reading even if interupted. If there is an actuall error though it will return -1. | |
/* Read "n" bytes from a socket descriptor. */ | |
int readn(SOCKET sd, void *vptr, unsigned int n) | |
{ | |
unsigned int nleft; | |
int nread; | |
char *ptr; | |
ptr = (char*)vptr; | |
nleft = n; | |
while (nleft > 0) { | |
if ( (nread = recv(sd, ptr, nleft, 0)) < 0) { | |
if (errno == EINTR) { | |
nread = 0; /* and call read() again */ | |
} else { | |
return (-1); | |
} | |
} else if (nread == 0) { | |
break; /* EOF */ | |
} | |
nleft -= nread; | |
ptr += nread; | |
} | |
return (n - nleft); /* return >= 0 */ | |
} | |
// You could make your own connect to host, where you can pass in IP and port. | |
// I just wanted something to keep trying to connect and send my init info. | |
//CONNECTTOHOST – Connects to a remote host | |
bool ConnectToHost() | |
{ | |
int PortNo = 47999; | |
char* IPAddress = "127.0.0.1"; | |
//Start up Winsock… | |
WSADATA wsadata; | |
int error = WSAStartup(0x0202, &wsadata); | |
//Did something happen? | |
if (error) { | |
return false; | |
} | |
//Did we get the right Winsock version? | |
if (wsadata.wVersion != 0x0202) | |
{ | |
WSACleanup(); //Clean up Winsock | |
return false; | |
} | |
//Fill out the information needed to initialize a socket… | |
SOCKADDR_IN target; //Socket address information | |
target.sin_family = AF_INET; // address family Internet | |
target.sin_port = htons (PortNo); //Port to connect on | |
target.sin_addr.s_addr = inet_addr (IPAddress); //Target IP | |
mySocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); //Create socket | |
if (mySocket == INVALID_SOCKET) | |
{ | |
return false; //Couldn't create the socket | |
} | |
//Try connecting... | |
if (connect(mySocket, (SOCKADDR *)&target, sizeof(target)) == SOCKET_ERROR) | |
{ | |
return false; //Couldn't connect | |
} else { | |
// So that data is sent when you want it sent instead of queuing up. | |
//disable nagle | |
char value = 1; | |
setsockopt( mySocket, IPPROTO_TCP, TCP_NODELAY, &value, sizeof( value ) ); | |
SomethingPacket_Init packet; | |
packet.id = 0; | |
packet.value = 0; | |
int iResult = writen(mySocket, (const char*)&packet, sizeof(SomethingPacket_Init)); | |
if (iResult == SOCKET_ERROR) { | |
Log.Write("Init: Send failed with error: %d", WSAGetLastError()); // I have a log write class but im going to remove it soon since I am done testing. | |
// If you want it ill link it in another gist somewhere just ask me. | |
closesocket(mySocket); | |
WSACleanup(); | |
ConnectToHost(); | |
return false; | |
} | |
return true; //Success | |
} | |
} | |
// Receiving data. | |
int iResult = readn(mySocket, (char*)&somebuffer, somelength); | |
if (iResult == SOCKET_ERROR) { | |
Log.Write("Something: Recv failed with error: %d", WSAGetLastError()); | |
closesocket(mySocket); | |
WSACleanup(); | |
ConnectToHost(); | |
return; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment