Skip to content

Instantly share code, notes, and snippets.

@LiamKarlMitchell
Created January 23, 2016 07:44
Show Gist options
  • Save LiamKarlMitchell/d3d5a2a50d82d5c7efa2 to your computer and use it in GitHub Desktop.
Save LiamKarlMitchell/d3d5a2a50d82d5c7efa2 to your computer and use it in GitHub Desktop.
// 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