Re: Sockets slow on Macintosh
Re: Sockets slow on Macintosh
- Subject: Re: Sockets slow on Macintosh
- From: Vincent Lubet <email@hidden>
- Date: Wed, 6 Apr 2005 08:58:49 -0700
When sending small messages to emulate transactions, you have to use
the socket option TCP_NODELAY - see man page tcp(4).
Vincent
On Apr 5, 2005, at 3:39 PM, Tron Thomas wrote:
I am working on a cross platform project that takes a long time to
start up on the Macintosh. Some investigates indicate that a large
portion of the slowness is related to the use of sockets for
communicating information between different processes.
To test this idea, I have written a much simpler client/server
implementation that simulates what the original code tries to do.
I ran this new implementation on an G4 iMac with 512 Megabytes of
RAM, running at 800 Megahertz, and using Mac OS X 10.3.8. I sent
370 text messages from the client to the server. The process took
over a minute and a half to complete. I ran the same program on an
Intel Pentium IV with 512 Megabytes of RAM, running at 1.7
Gigahertz, and using Fedora Core 3 Linux. That system took just
over 5 seconds to complete the same number of iterations.
Given that the Intel system can perform the program so quickly,
what can be changed in the code so the Macintosh can have
comparable speed? Below are the source listing both the client and
server, the Makefile for building the programs, and a Bash shell
script used to aid in testing. I would appreciated any feedback,
anyone has to offer.
+-------------+
| Server Code |
+-------------+
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h> // needed for strerror
#include <errno.h>
#include <iostream>
#include <stdexcept>
#include <vector>
#include <string>
using std::string;
namespace
{
void ThrowError
(
const char* pszPrefix
)
{
string strError = pszPrefix;
strError += ::strerror(errno);
strError += '\n';
throw std::runtime_error(strError);
}
}
int main()
{
const short nPORT = 8979;
const int nMAXIMUM_CONNECTIONS = 5;
const int nINVALID_SOCKET = -1;
using std::cerr;
using std::clog;
using std::cout;
int nServerSocket = ::socket(AF_INET, SOCK_STREAM, 0);
if(0 == nServerSocket){
cerr << "Failed to create the server socket.\n";
return 0;
}
sockaddr_in address;
::memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = ::inet_addr("127.0.0.1");
address.sin_port = htons(nPORT);
int connection = nINVALID_SOCKET;
try{
if(0 > ::bind(nServerSocket, reinterpret_cast<sockaddr*>
(&address),
sizeof(address))){
::ThrowError("The following error occurred binding
to the server "
"socket:\n");
}
if(0 > ::listen(nServerSocket, nMAXIMUM_CONNECTIONS)){
::ThrowError("The following error occurred creating the
listening "
"queue.\n");
}
cout << "The server is running and waiting for connections.\n";
bool bRun = true;
while(bRun){
fd_set readSet;
FD_ZERO (&readSet);
FD_SET(nServerSocket, &readSet);
timeval timeout = {5, 0};
int nResult = ::select(FD_SETSIZE, &readSet, NULL, NULL,
&timeout);
if(0 > nResult){
::ThrowError("The following error occurred while waiting
for a "
"connection:\n");
}
if(0 == nResult){
clog << "Timed out waiting for a connection.\n";
continue;
}
cout << "Accepting a client connection.\n";
if(FD_ISSET(nServerSocket, &readSet)){
sockaddr_in client_address = address;
socklen_t client_address_len =
static_cast<socklen_t>(sizeof(client_address));
connection = ::accept(nServerSocket,
reinterpret_cast<sockaddr*>(&client_address),
&client_address_len);
if(0 > connection){
::ThrowError("The following error occrured accepting
a client "
"connection:\n");
}
}
size_t bufferSize;
nResult = ::recv(connection, &bufferSize, sizeof
(bufferSize), 0);
if(nResult != sizeof(bufferSize)){
::ThrowError("The follow error occurred trying to read
the buffer "
"size:\n");
}
std::vector<char> buffer(bufferSize);
nResult = ::recv(connection, &(buffer[0]), bufferSize, 0);
string message;
if(nResult == static_cast<int>(bufferSize)){
message.assign(buffer.begin(), buffer.end());
}
else
{
::ThrowError("The following error ocurred reading the
text:\n");
}
if(0 == message.compare("stop")){
clog << "Stopping the server.\n";
bRun = false;
}
else{
clog << "Received the following client data:\n" <<
message << '\n';
}
message = "?return_code=PASS";
size_t length = message.size();
nResult = ::send(connection, &length, sizeof(length), 0);
if(sizeof(length) != nResult){
::ThrowError("The following error occurred sending the
message "
"reply size.\n");
}
nResult = ::send(connection, message.c_str(), length, 0);
if(nResult != static_cast<int>(length)){
::ThrowError("The following error occurred sending the
reply "
"message.\n"); }
::close(connection);
connection = nINVALID_SOCKET;
}
}
catch(const std::exception& error){
cerr << error.what() << std::endl;
if(nINVALID_SOCKET != connection){
::close(connection);
connection = nINVALID_SOCKET;
}
}
::close(nServerSocket);
return 0;
}
+-------------+
| Client Code |
+-------------+
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h> // needed for strerror
#include <stdlib.h>
#include <errno.h>
#include <iostream>
#include <stdexcept>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
using std::string;
namespace
{
void ThrowError
(
const char* pszPrefix
)
{
string strError = pszPrefix;
strError += ::strerror(errno);
strError += '\n';
throw std::runtime_error(strError);
}
char RandomChar()
{
return(' ' + (::rand() % 95));
}
void CreateRandomMessage
(
string* pstrMessage
)
{
if(NULL == pstrMessage){
return;
}
pstrMessage->erase();
size_t size = ::rand() % 100;
// Allow only an 8% chance of large size buffers
if(size >= 8){
size = 40 + ::rand() % 40;
}
else{
size = 100 + ::rand() % 250;
}
std::insert_iterator<string> insert(*pstrMessage,
pstrMessage->begin());
std::generate_n(insert, size, RandomChar);
}
}
int main
(
int nArgumentCount,
const char* pszArguments[]
)
{
const short nPORT = 8979;
using std::cerr;
using std::clog;
using std::cout;
int nServerSocket = ::socket(AF_INET, SOCK_STREAM, 0);
if(0 > nServerSocket){
cerr << "Failed to create the server socket.\n";
return 0;
}
try{
sockaddr_in serverAddress;
::memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = ::inet_addr("127.0.0.1");
serverAddress.sin_port = htons(nPORT);
cout << "Connecting to the server...\n";
int nResult = ::connect(nServerSocket,
reinterpret_cast<sockaddr*>(&serverAddress),
sizeof(serverAddress));
if(0 != nResult){
::ThrowError("The following error occurred establishing a
connection "
"to the server:\n");
}
string strMessage;
if(1 < nArgumentCount){
strMessage = pszArguments[1];
}
else{
::srand(::getpid());
::CreateRandomMessage(&strMessage);
}
size_t length = strMessage.size();
clog << "Sending " << length << " bytes of data to the
server.\n";
nResult = ::send(nServerSocket, &length, sizeof(length), 0);
if(0 > nResult){
::ThrowError("The following error occurred sending data
size:\n");
}
nResult = ::send(nServerSocket, strMessage.c_str(), length, 0);
if(nResult == static_cast<int>(length)){
clog << "Sent message '" << strMessage << "' to the server.
\n";
} else{
::ThrowError("The following error occurred sending data:\n");
}
cout << "Waiting for the server reply...\n";
size_t bufferSize;
nResult = ::recv(nServerSocket, &bufferSize, sizeof
(bufferSize), 0);
if(0 > nResult){
::ThrowError("The following error occurred reading the
buffer "
"size:\n");
}
std::vector<char> buffer(bufferSize);
nResult = ::recv(nServerSocket, &(buffer[0]), bufferSize, 0);
if(nResult != static_cast<int>(bufferSize)){
::ThrowError("The following error occurred getting the
reply data.\n");
}
string strReply(buffer.begin(), buffer.end());
clog << "The server replied with '" << strReply << "'.\n";
}
catch(const std::exception& error){
cerr << error.what() << std::endl;
}
::close(nServerSocket);
return 0;
}
+----------+
| Makefile |
+----------+
CXX = /usr/bin/g++
CFLAGS = -g3 -Wall -ansi -pedantic
.SUFFIXES: .cpp
.cpp.o:
$(CXX) $(CFLAGS) -c $< -o $@
all: Server Client
Server: Server.o
$(CXX) -Wall $< -o $@
Client: Client.o
$(CXX) -Wall $< -o $@
clean:
rm -f Client
rm -f Server
rm -f *.o
+--------------+
| Shell Script |
+--------------+
#! /bin/sh
if [ $# -gt 0 ]; then
passes=$1
else
passes=10
fi
echo "Running $passes test passes..."
while [ $passes -gt 0 ]
do
./Client
passes=$[$passes - 1]
echo "$passes passes left."
done
./Client stop
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Macnetworkprog mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
40apple.com
This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Macnetworkprog mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden