Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
pseudorandom name
May 6, 2007

Its called fcvt_r()

Adbot
ADBOT LOVES YOU

Risket
Apr 3, 2004
Lipstick Apathy
I'm having a bit of information overload with a work project, and could use some guidance.

Note: I'm a total beginner at with C++ and programming in general.

I'd trying to write a Windows program that will accept a series command line arguments, and based off those it will display video in the correct format (I work for a company that makes frame grabber products for medical devices) in a window.

I'm using Visual Studio 2010, and the program will be run on Windows 7 and maybe 8 using the command prompt.

The problem that I'm running into is that I keep reading various articles that say I should use GetCommandLine(), other say I should use __argv/__argc, some say lpCmdLine, and others say I should use a third party library like Boost.program_options() or getopt. __argv works in my testing, but I keep reading that I shouldn't use __argv but I having trouble finding out why. Also, should I be using ASCII or Unicode? Does it matter?

Edit: I should have said, Visual Studio generated the program entrance as:
code:
 int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

I guess what Im asking is what would be the best way to capture the command Iine arguments and aprse them from there.

Thanks

Risket fucked around with this message at 17:23 on Nov 23, 2014

nielsm
Jun 1, 2009



Since you're using WinMain() as entry point, I assume you're writing a windowed application, as opposed to a console application.

Windows passes command line arguments differently from Unix systems; where Unix passes the commandline as an array of strings, Windows passes it as a single long string without separation. However Windows does provide a function that can do a standard split into arguments.

C++ code:
int APIENTRY tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
  inc argc;
  LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc);
  // argv points to argc count of unicode strings, each containing one commandline argument
}
You should definitely use Unicode on Windows. Writing programs to the ANSI APIs is deprecated, is almost guaranteed to cause bugs if you use the program on a different language version of Windows than what you're developing for, and locks you out of some newer APIs altogether.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

nielsm posted:

You should definitely use Unicode on Windows. Writing programs to the ANSI APIs is deprecated, is almost guaranteed to cause bugs if you use the program on a different language version of Windows than what you're developing for, and locks you out of some newer APIs altogether.
Aren't the W versions of functions a horrible kind of Unicode? Is there no UTF-8 for Windows GUI stuff?

raminasi
Jan 25, 2005

a last drink with no ice

nielsm posted:

Since you're using WinMain() as entry point, I assume you're writing a windowed application, as opposed to a console application.

Alternatively, the application is supposed to be a console application, and the project was just set up wrong. Risket, when you created your project in Visual Studio, did you create an empty console project, or some other project type? In a console project, your entry point would be called main, and it would have argc and argv parameters for you to use. (getopt and Boost.program_options are helpers for parsing argv out, but if you're a novice, it's better to just do it yourself so you have fewer things to think about.)

asur
Dec 28, 2012

Risket posted:

I'm having a bit of information overload with a work project, and could use some guidance.

Note: I'm a total beginner at with C++ and programming in general.

I'd trying to write a Windows program that will accept a series command line arguments, and based off those it will display video in the correct format (I work for a company that makes frame grabber products for medical devices) in a window.

I'm using Visual Studio 2010, and the program will be run on Windows 7 and maybe 8 using the command prompt.

The problem that I'm running into is that I keep reading various articles that say I should use GetCommandLine(), other say I should use __argv/__argc, some say lpCmdLine, and others say I should use a third party library like Boost.program_options() or getopt. __argv works in my testing, but I keep reading that I shouldn't use __argv but I having trouble finding out why. Also, should I be using ASCII or Unicode? Does it matter?

Edit: I should have said, Visual Studio generated the program entrance as:
code:
 int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
I guess what Im asking is what would be the best way to capture the command Iine arguments and aprse them from there.

Thanks

_argv and __argc are globals defined in stdlib.h by VC, however they are not standard definitions and should be avoided if possible. You could parse lpCmdLine yourself or use GetCommandLineW and CommandLineToArgvW to parse the command line into separate strings. I don't know why, but CommandLineToArgvW expects a non-empty string, which GetCommandLineW will return as the command line will always contain the program name, and thus lpCmdLine should not be passed to it.

edit: Just to followup on what I said above about not using the globals is for the WIN GUI eentry point. If you have int main(int argc, char ** argv) as your function prototype then use the argc and argv inputs.

asur fucked around with this message at 17:43 on Nov 23, 2014

nielsm
Jun 1, 2009



roomforthetuna posted:

Aren't the W versions of functions a horrible kind of Unicode? Is there no UTF-8 for Windows GUI stuff?

It's UTF-16, and it's the only way to talk Unicode to Windows. It's also what it uses internally. As long as you don't try to chop up strings by characters but just treat them as opaque values that can be manipulated by library functions, you should be fine. (There's UTF-16 surrogate pairs, and then there's the much be devious cases of multiple codepoints affecting each other in complex scripts. It's usually only relevant when you're actually working with natural language text.)

Sure, you can use UTF-8 in Windows software, but not for calling Win32 APIs. Theoretically it could be possible to set the ANSI-codepage for your process to 65001 which is UTF-8 and use the ANSI API with UTF-8 strings, but Microsoft doesn't test that so it doesn't actually work.

Risket
Apr 3, 2004
Lipstick Apathy

GrumpyDoctor posted:

Alternatively, the application is supposed to be a console application, and the project was just set up wrong. Risket, when you created your project in Visual Studio, did you create an empty console project, or some other project type? In a console project, your entry point would be called main, and it would have argc and argv parameters for you to use. (getopt and Boost.program_options are helpers for parsing argv out, but if you're a novice, it's better to just do it yourself so you have fewer things to think about.)
I used a Win32 project, and set it up as a Windows application. I did this because I'm using an existing SDK sample as my guide, which you just edit a function parameter to display video in the format that you want. Right now I have dozens of these little programs in a bunch of directories, and I'm trying to make one program that can replace all the little ones. I'm basically stuck using this cause I don't know enough to write something different, and our actual software engineers are busy with mission critical things.

Edit: I'll just use Unicode and figure out how to use GetCommandLine(). Thanks guys.

Risket fucked around with this message at 18:01 on Nov 23, 2014

nielsm
Jun 1, 2009



Risket posted:

Edit: I'll just use Unicode and figure out how to use GetCommandLine(). Thanks guys.

The code snippet I posted above shows exactly how you should use GetCommandLineW(), together with CommandLineToArgvW(), to get something you can work with without too much hassle.

Risket
Apr 3, 2004
Lipstick Apathy

nielsm posted:

The code snippet I posted above shows exactly how you should use GetCommandLineW(), together with CommandLineToArgvW(), to get something you can work with without too much hassle.
I missed that, thank you!

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av

Risket posted:

I'm using Visual Studio 2010, and the program will be run on Windows 7 and maybe 8 using the command prompt.

If you run a GUI program from the command prompt, the command prompt will not wait for it to terminate. If it's important that the command prompt knows when your program terminates (for example if it has to be called from a batch script), then compile it as a console application. Yes, console applications can create windows

Risket posted:

__argv works in my testing, but I keep reading that I shouldn't use __argv but I having trouble finding out why.

It's non-standard as you can tell from the double underscore, but who cares. Me, I would use wmain (int wmain(int argc, wchar_t **argv)), and then manually set the program as a GUI program in the linker settings (look in the project's settings, look for "subsystem" under linker settings), but WinMain with __argc and __argv is perfectly fine. Not sure if you really need getopt/Boost.ProgramOptions, depends on how complex your command line arguments are

Risket posted:

Also, should I be using ASCII or Unicode? Does it matter?

Use Unicode. I don't know if it matters to your particular application, but Unicode is pretty much standard everywhere nowadays

If you need to interact with third party Unicode libraries, Windows Unicode strings are in UTF-16 format and need to be converted if you need UTF-8

Risket posted:

Edit: I should have said, Visual Studio generated the program entrance as:
code:
 int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

All arguments to WinMain are data you can get from GetModuleHandle, GetStartupInfo or GetCommandLine. There's nothing magic to them, and the WinMain parameters are only kept for backwards compatibility with 16 bit Windows (where hPrevInstance could be something other than NULL for example), so don't read too much into them

Risket posted:

I guess what Im asking is what would be the best way to capture the command Iine arguments and aprse them from there.

Get them with argc/argv or __argc/__argv, parse them however you like

I wouldn't use CommandLineToArgvW because it uselessly duplicates work the C/C++ runtime library already does

roomforthetuna posted:

Aren't the W versions of functions a horrible kind of Unicode?

UTF-16, it's alright

roomforthetuna posted:

Is there no UTF-8 for Windows GUI stuff?

No and it's a little silly, but that's how it is

Risket
Apr 3, 2004
Lipstick Apathy

hackbunny posted:

If you run a GUI program from the command prompt, the command prompt will not wait for it to terminate. If it's important that the command prompt knows when your program terminates (for example if it has to be called from a batch script), then compile it as a console application. Yes, console applications can create windows
It made sense in my head that they could, but what the gently caress do I know. I'll read up on this, thanks.

And here I was hoping that this would be a small project that would last a couple of days.

FearIt
Mar 11, 2007
Hello again COC,

For the past couple of days I have been trying to use libCurl to log into a website ( draftkings.com ) and try to scrape the contest list. I am pounding my head on the wall as to why my curl requests are not being accepted. The following is a summary of my code ( mostly just an example from the curl website ). Am I using curl wrong?

code:
#include <stdio.h>
#include <curl/curl.h>

int main(void)
{
  CURL *curl;
  CURLcode res;
  
  /* In windows, this will init the winsock stuff */
  curl_global_init(CURL_GLOBAL_ALL);
  
  /* get a curl handle */
  curl = curl_easy_init();
  if(curl) {
    /* First set the URL that is about to receive our POST. This URL can
     just as well be a [url]https://[/url] URL if that is what should receive the
     data. */
    curl_easy_setopt(curl, CURLOPT_URL, "https://www.draftkings.com/");
    
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    
    /* Now specify the POST data */
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "ExistingUserRadio=1&Username=xxxMYUSERxxx&Password=xxxMyPassxxx");
    
    /* Perform the request, res will get the return code */
    res = curl_easy_perform(curl);
    /* Check for errors */
    if(res != CURLE_OK)
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));
    
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
  curl_global_cleanup();
  return 0;
}

Top Bunk Wanker
Jan 31, 2005

Top Trump Anger
Is there a plain-English, near retard level explanation for how to use the Boost Graph Library to put together a directed graph with weighted edges out there anywhere, and, if so, may I read it?

astr0man
Feb 21, 2007

hollyeo deuroga

FearIt posted:

For the past couple of days I have been trying to use libCurl to log into a website ( draftkings.com ) and try to scrape the contest list. I am pounding my head on the wall as to why my curl requests are not being accepted. The following is a summary of my code ( mostly just an example from the curl website ). Am I using curl wrong?

What do you mean by your requests aren't being accepted? What is the error you get, and are you sure that http post actually works in the first place (i.e. when you aren't trying to do it in libcurl)?

FearIt
Mar 11, 2007

astr0man posted:

What do you mean by your requests aren't being accepted? What is the error you get, and are you sure that http post actually works in the first place (i.e. when you aren't trying to do it in libcurl)?

I believed that a correct POST would result in the return data to contain account specific information. My test for success involves looking for my current account balance, instead looking over the return, I see a login prompt again. It might indeed be that the post does not work, I gathered the filenames from the <form> block and am pretty sure I'm getting it right,, but I may be wrong.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

FearIt posted:

I believed that a correct POST would result in the return data to contain account specific information. My test for success involves looking for my current account balance, instead looking over the return, I see a login prompt again. It might indeed be that the post does not work, I gathered the filenames from the <form> block and am pretty sure I'm getting it right,, but I may be wrong.
Chrome has some pretty cool debug-aid features that include being able to examine the full request that was sent, which you could use as a much more reliable and convenient way to get POST data than trying to figure out what it will be by looking at HTML forms.

OddObserver
Apr 3, 2009
You may need to appropriate encoding header (Content-Type: application/x-www-form-urlencoded). Also for heaven's sake, you're not really turning off verification of peer's SSL certificate, are you?

OddObserver fucked around with this message at 14:02 on Nov 25, 2014

Risket
Apr 3, 2004
Lipstick Apathy
I work for a company that manufacturers frame grabber boards. (http://en.wikipedia.org/wiki/Frame_grabber)
As I said earlier, I'm trying to write an application that will take a series of command line arguments to accept the video format and input that is being sent to the board, and configure the device to accept that video.

Now, thanks to the help I got earlier, I am able get the command line arguments, and parse them using std::find. However, the problem is that there are 57 different video formats/resolutions/etc... that could be used.

The video formats are specified in a header file, and are GUIDs. You select the GUID to use, then insert it as a referenced function parameter. Here is an example:
code:
Header File:
DEFINE_GUID(INPUT_CompNTSCCCIR, 
0x1571d839, 0x1b03, 0x4318, 0x95, 0xbf, 0x6, 0x89, 0x65, 0x1c, 0x8, 0x7c);

.CPP File:
hSrc = dpSetDeviceInput(hDevice, &INPUT_CompNTSCCCIR, 0, 0);
Like I said, there are 57 of them, and since I can't use the contents of a string variable as a function parameter, what would be the best way of doing this without using 57 if statements?

Please note that I'm pretty much a beginner at this...

Thanks

nielsm
Jun 1, 2009



Make a static lookup-table mapping between sensible strings and the GUIDs.

C++ code:
// In implementation (.cpp) file top-level scope
struct NamedGuid {
  std::string name;
  GUID const *guid;
};
static const NamedGuid format_guid_names[] = {
  {"ntsc-ccir", &INPUT_CompNTSCCCIR},
  {"pal-ccir", &INPUT_CompPALCCIR},
  // ... more pairings ...
  {"", nullptr} // final sentinel
};
The array of format GUID names is terminated with a sentinel element which is not actually valid, but can be detected when searching through the list, like this:
C++ code:
GUID const * get_format_guid_by_name(std::string const &name) {
  for (auto guid_name = format_guid_names; guid_name.guid != nullptr; ++guid_name) {
    if (guid_name.name == name)
      return guid_name.guid;
  }
  // no matching guid was found, return a nullptr to indicate this
  return nullptr;
}

Risket
Apr 3, 2004
Lipstick Apathy

nielsm posted:

Make a static lookup-table mapping between sensible strings and the GUIDs.

C++ code:
// In implementation (.cpp) file top-level scope
struct NamedGuid {
  std::string name;
  GUID const *guid;
};
static const NamedGuid format_guid_names[] = {
  {"ntsc-ccir", &INPUT_CompNTSCCCIR},
  {"pal-ccir", &INPUT_CompPALCCIR},
  // ... more pairings ...
  {"", nullptr} // final sentinel
};
The array of format GUID names is terminated with a sentinel element which is not actually valid, but can be detected when searching through the list, like this:
C++ code:
GUID const * get_format_guid_by_name(std::string const &name) {
  for (auto guid_name = format_guid_names; guid_name.guid != nullptr; ++guid_name) {
    if (guid_name.name == name)
      return guid_name.guid;
  }
  // no matching guid was found, return a nullptr to indicate this
  return nullptr;
}
I have no idea what half this poo poo is, but I'm going to Google the hell out of all of it to figure it out.

Thank you very much!

Mr. Crow
May 22, 2008

Snap City mayor for life

Risket posted:

I have no idea what half this poo poo is, but I'm going to Google the hell out of all of it to figure it out.

Thank you very much!

Basically you're creating a map ahead of time between friendly-name <-> guid so you can just directly pull out the data you want.


That being said I'm curious why he's not just making a std::unordered_map<> (newbie as well)?

Risket
Apr 3, 2004
Lipstick Apathy

Mr. Crow posted:

Basically you're creating a map ahead of time between friendly-name <-> guid so you can just directly pull out the data you want.


That being said I'm curious why he's not just making a std::unordered_map<> (newbie as well)?
What is the difference? Is there a problem with what he posted?

nielsm
Jun 1, 2009



Mr. Crow posted:

Basically you're creating a map ahead of time between friendly-name <-> guid so you can just directly pull out the data you want.


That being said I'm curious why he's not just making a std::unordered_map<> (newbie as well)?

You probably could do that, but it'd be uncomfortable syntax-wise if the compiler doesn't fully support initializer-lists. As far as I understand, Risket is using MSVC where that still isn't such a good idea yet.

But I think it should look something like this:
C++ code:
#include <unordered_map>

static const std::unordered_map<std::string, GUID const *> format_guid_names {
  {"ntsc-ccir", &INPUT_CompNTSCCCIR},
  {"pal-ccir", &INPUT_CompPALCCIR},
  // ... more pairsings ...
  // but no sentinel needed
};

GUID const * get_format_guid_by_name(std::string const &name) {
  auto it = format_guid_names.find(name);
  if (it != format_guid_names.end())
    return it.second;
  else
    return nullptr;
}

pseudorandom name
May 6, 2007

Risket posted:

What is the difference? Is there a problem with what he posted?

nielsm's suggestion (a normal array) has no complexity in the setup at the expense of a linear search at runtime, which in practice for a 57 element list searched once at program startup is not a problem.

Mr. Crow's suggestion (a std::unordered_map<>) trades some complexity in the setup for fast lookup times, since std::unordered_map<> is required to have amortized constant time complexity and in practice ends up being a hash table. This is what you'd want to do if you search your list frequently or had thousands of elements instead of just 57.

Risket
Apr 3, 2004
Lipstick Apathy

nielsm posted:

You probably could do that, but it'd be uncomfortable syntax-wise if the compiler doesn't fully support initializer-lists. As far as I understand, Risket is using MSVC where that still isn't such a good idea yet.

But I think it should look something like this:
C++ code:
#include <unordered_map>

static const std::unordered_map<std::string, GUID const *> format_guid_names {
  {"ntsc-ccir", &INPUT_CompNTSCCCIR},
  {"pal-ccir", &INPUT_CompPALCCIR},
  // ... more pairsings ...
  // but no sentinel needed
};

GUID const * get_format_guid_by_name(std::string const &name) {
  auto it = format_guid_names.find(name);
  if (it != format_guid_names.end())
    return it.second;
  else
    return nullptr;
}
Yeah, I should have mentioned that I'm using Visual Studio 2010

Risket
Apr 3, 2004
Lipstick Apathy

nielsm posted:

You probably could do that, but it'd be uncomfortable syntax-wise if the compiler doesn't fully support initializer-lists. As far as I understand, Risket is using MSVC where that still isn't such a good idea yet.

But I think it should look something like this:
C++ code:
#include <unordered_map>

static const std::unordered_map<std::string, GUID const *> format_guid_names {
I'm getting an "expected a declaration" error on this first curly brace.

This is a function declaration, right?

Risket fucked around with this message at 19:48 on Nov 25, 2014

sarehu
Apr 20, 2007

(call/cc call/cc)

Risket posted:

I'm getting an "expected a declaration" error on this first curly brace.

Try adding an equals sign. If that doesn't work, I don't know.

Mr. Crow
May 22, 2008

Snap City mayor for life

Risket posted:

I'm getting an "expected a declaration" error on this first curly brace.

This is a function declaration, right?

http://stackoverflow.com/questions/12654394/initializer-list-not-working-with-vector-in-visual-studio-2012

Initializer lists are only supported in VS2013, if you're using VS. Otherwise the first post has the correct syntax.

nielsm
Jun 1, 2009



I think you actually need the upcoming VC 2015 for full initializer list support, there are some bugs with it in 2013 still.

Risket
Apr 3, 2004
Lipstick Apathy

nielsm posted:


The array of format GUID names is terminated with a sentinel element which is not actually valid, but can be detected when searching through the list, like this:
C++ code:
GUID const * get_format_guid_by_name(std::string const &name) {
  for (auto guid_name = format_guid_names; guid_name.guid != nullptr; ++guid_name) {
    if (guid_name.name == name)
      return guid_name.guid;
  }
  // no matching guid was found, return a nullptr to indicate this
  return nullptr;
}
I apologize for making GBS threads up this thread with lots of questions, but I don't know enough to know the correct term to search for.

Now I'm getting an "expression must have a class type" Intellisense error on every guid_name.name/guid instance following the declaration in the for loop.

Following compile:
error C2228: left of '.guid' must have class/struct/union
type is 'const NamedGuid *'
did you intend to use '->' instead?

Risket fucked around with this message at 20:27 on Nov 25, 2014

nielsm
Jun 1, 2009



Risket posted:

I apologize for making GBS threads up this thread with lots of questions, but I don't know enough to know the correct term to search for.

Now I'm getting an "expression must have a class type" error on every guid_name.name/guid instance following the declaration in the for loop.

Sorry, my fault there for typing without thinking.

Should all be guid_name->name and guid_name->guid for dereferencing member lookup, i.e. arrow instead of dot.

Risket
Apr 3, 2004
Lipstick Apathy

nielsm posted:

Sorry, my fault there for typing without thinking.

Should all be guid_name->name and guid_name->guid for dereferencing member lookup, i.e. arrow instead of dot.
No worries, thank you very much for your help.

hooah
Feb 6, 2006
WTF?
I'm working on doing part-of-speech tagging with the Viterbi algorithm. We've been given a table of word/tag counts:


We also have a table of bigram probabilities (incomplete):


I need to be able to grab a word from an input sentence and look up counts and probabilities from these two tables. I can set up 2-d arrays for the tables, that's no problem, but getting the indices into those tables is proving problematic. I thought of making enums for the words and tags, but that would leave me making a bunch of if/then statements to figure out which word is being looked at. Is there a standard/normal way to do something like this?

giogadi
Oct 27, 2009

hooah posted:

I need to be able to grab a word from an input sentence and look up counts and probabilities from these two tables. I can set up 2-d arrays for the tables, that's no problem, but getting the indices into those tables is proving problematic. I thought of making enums for the words and tags, but that would leave me making a bunch of if/then statements to figure out which word is being looked at. Is there a standard/normal way to do something like this?

You can use a hash table (unordered_map, C++11 only) or a map for this. For the map, your keys could be strings representing each of the possible words or tags.

hooah
Feb 6, 2006
WTF?

giogadi posted:

You can use a hash table (unordered_map, C++11 only) or a map for this. For the map, your keys could be strings representing each of the possible words or tags.

Y'know, I'd done this for the words, then for some reason my brain went "That won't work for the tags!". Thank you!

FearIt
Mar 11, 2007

roomforthetuna posted:

Chrome has some pretty cool debug-aid features that include being able to examine the full request that was sent, which you could use as a much more reliable and convenient way to get POST data than trying to figure out what it will be by looking at HTML forms.

This provided exactly what I was looking for. I mimicked the rest of the POST data and got the success condition. Thanks!

The Gay Bean
Apr 19, 2004
I'm having an issue getting some code I wrote on Linux working on OSX.. The following code snippet sums it up.

Client:
code:
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <netdb.h>
#include <iostream>
#include <string.h>

int main()
{
    struct addrinfo structHints, *pResult;
    memset(&structHints, 0, sizeof structHints);
    structHints.ai_family = AF_UNSPEC;
    structHints.ai_socktype = SOCK_STREAM;
    char strPort[6];
    sprintf(strPort, "%u", 1321);
    getaddrinfo("192.168.0.2", strPort, &structHints, &pResult);
    //getaddrinfo("192.168.0.5", strPort, &structHints, &pResult);
    int socketClient = socket(pResult->ai_family,
            pResult->ai_socktype,
            pResult->ai_protocol);
    int nFlagToSet = 1;
    // just to be safe and make sure we're not buffering
    int nResult = setsockopt(socketClient,
                            IPPROTO_TCP,
                            TCP_NODELAY,
                            (char *) &nFlagToSet,
                            sizeof(int));
    std::cout << "Trying to connect..." << std::endl;
    int nConnectReturn = -1;
    nResult = connect(socketClient, pResult->ai_addr, pResult->ai_addrlen);
    std::cout << "Connected." << std::endl;
    int nCount = 0;
    std::string strToSend;
    while (strToSend.size() < 999)
        strToSend.push_back('a');
    char strServerReply[1000];
    while (nCount < 1000)
    {
        printf("Waiting to receive message.\n");
        ::recv(socketClient , strServerReply , 1000 , 0);
        printf("Received from server: %s\n",strServerReply);
        printf("Sending to server.\n");
        int nBytes = ::send(socketClient, strToSend.c_str(), 1000, 0);
        nCount++;
    }
    return 0;
}
And server:
code:
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <netdb.h>
#include <iostream>
#include <string.h>
#include <fcntl.h>

int main()
{
    sockaddr_in *addressServer = (sockaddr_in *) malloc(sizeof(struct sockaddr_in));
    memset(addressServer, 0, sizeof(struct sockaddr_in));
    addressServer->sin_family = AF_INET;
    addressServer->sin_addr.s_addr = htonl(INADDR_ANY);
    addressServer->sin_port = htons(1321);
    int socketServer = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    int nFlagToSet = 1;
    setsockopt(socketServer, IPPROTO_TCP, SO_REUSEADDR, &nFlagToSet, sizeof(nFlagToSet));
    ::bind(socketServer, (sockaddr *)addressServer, sizeof(*addressServer));
    while (true)
    {
        std::cout << "Listening." << std::endl;
        ::listen(socketServer, 1);

        sockaddr_in *clientAddr;
        long unsigned int caSize = sizeof(clientAddr);
        int socketClient = accept(socketServer, (struct sockaddr *)&clientAddr, (socklen_t *)&caSize);
        // just to be safe and make sure we're not buffering
        setsockopt(socketServer, IPPROTO_TCP, TCP_NODELAY, &nFlagToSet, sizeof(nFlagToSet));

        // On OSX, this loop is terribly slow unless this is uncommented. If
        // it's commented, send() and recv() frequently return -1.
        //fcntl(socketClient,F_SETFL,fcntl(socketClient,F_GETFL)|O_NONBLOCK);

        // Confirm that socket is in blocking mode
        std::cout << "Value of fcntl(socketClient,F_GETFL): "
            << fcntl(socketClient,F_GETFL) << ","
               << "Value of fcntl(socketClient,F_GETFL) | O_NONBLOCK): "
               << (fcntl(socketClient,F_GETFL) | O_NONBLOCK) <<
                  ", Press enter to continue." << std::endl;
        std::cin.ignore();

        std::cout << "Got connection. Beginning data loop." << std::endl;
        bool bConnected = true;
        int nCount = 0;
        std::string strToSend;
        while (strToSend.size() < 999)
            strToSend.push_back('a');
        char strClientReply[1000];
        while (nCount < 1000)
        {
            printf("Sending to client.\n");
            int nResult = ::send(socketClient, strToSend.c_str(), 1000, 0);
            printf("Sent. Waiting to receive message.\n");
            nResult = ::recv(socketClient , strClientReply , 1000 , 0);

            printf("Received from server: %s\n",strClientReply);
            nCount++;
        }
    }
    return 0;
}
Linux client and server: done in milliseconds.
Linux server and OSX client: Done in milliseconds.
OSX server and Linux/OSX client: I don't know how long, probably an hour.

I've controlled for TCP_NODELAY and blocking, and a blocking socket in Linux and OSX seem to behave completely differently. A recv() call for a socket spawned from an accept() call seems to go really slow on OSX, while it's fast on Linux. In OSX you can set the socket to nonblocking, but then recv() and send() start to return -1 occasionally. I can set the OSX socket to nonblocking mode, catch those -1 returns and retry until I've sent all my data; I guess this is what I'm supposed to do then? More to the point, is there some good, cross-platform wrapper for native socket functions, which all seem to behave differently in unexpected ways? Or do I just bandage it up with preprocessor macros?

The Gay Bean fucked around with this message at 17:26 on Nov 28, 2014

Zopotantor
Feb 24, 2013

...und ist er drin dann lassen wir ihn niemals wieder raus...

The Gay Bean posted:

Linux client and server: done in milliseconds.
Linux server and OSX client: Done in milliseconds.
OSX server and Linux/OSX client: I don't know how long, probably an hour.

I've controlled for TCP_NODELAY and blocking, and a blocking socket in Linux and OSX seem to behave completely differently. I can set the OSX socket to nonblocking mode, catch those -1 returns and retry until I've sent all my data; I guess this is what I'm supposed to do then? More to the point, is there some good, cross-platform wrapper for native socket functions, which all seem to behave differently in unexpected ways? Or do I just bandage it up with preprocessor macros?

You could use Wireshark to see what's actually going on.

Adbot
ADBOT LOVES YOU

hooah
Feb 6, 2006
WTF?
With printf, can I specify the number of exponent digits? I'm not going to have anything with more than a 2-digit exponent and I already formatted other output based on that assumption.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply