Sockets slow on Macintosh
Sockets slow on Macintosh
- Subject: Sockets slow on Macintosh
- From: Tron Thomas <email@hidden>
- Date: Tue, 05 Apr 2005 15:39:24 -0700
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:
This email sent to email@hidden