Проживание в Динамической Среде TCP/IP
Этот technote описывает часть запутанности контакта с TCP/IP в динамической среде, такой как предоставленный Mac OS. В частности это описывает, как записать сокеты BSD и Открыть код Transport, правильно обрабатывающий размещение в разных сетях (многократные IP-адреса), каналы коммутируемого доступа, сон и пробуждение на PowerBook (или современный рабочий стол), модемное разъединение и пользовательское реконфигурирование.
Это примечание направлено на всех разработчиков, непосредственно использующих сетевой APIs, предоставленный Mac OS X и традиционным Mac OS.
Динамические Основные принципы TCP/IP
Много программ TCP/IP делают ложные предположения о среде TCP/IP. В то время как предположения как «эта машина имеют TCP/IP, поэтому она должна иметь IP-адрес», и «IP-адрес машины не изменится», были допустимы для рабочих станций на университетском Ethernet, они не содержат для PowerBook, выполняющего Mac OS, соединенный через PPP. В частности, следующее неочевидные последствия динамической среды TCP/IP Mac OS:
Компьютер не имеет IP-адреса, пока он не получил тот. Например, если компьютер сконфигурирован для получения адреса через PPP, он не получает адрес до модемных подключений.
IP-адрес компьютера может изменяться в течение долгого времени. Например, если арендный договор DHCP компьютера истечет, то штабель TCP/IP согласует для нового адреса, который может не совпасть со старым адресом.
Чтобы быть совместимым с размещением в разных сетях (компьютер с многократными IP-адресами), Ваше приложение не должно предполагать, что машина имеет просто единственный IP-адрес, или что все IP-адреса машины эквивалентны.
Пользователь может сконфигурировать каналы коммутируемого доступа (такие как Mac OS X PPP, ARA и другие) для «Соединения автоматически при запущении приложений TCP/IP». Если Ваше приложение использует службы TCP/IP без явного пользовательского запроса, пользователь может быть поражен для нахождения их модемного набора номера в середине ночи.
На традиционном Mac OS штабель TCP/IP может разгрузиться из памяти. Когда это произойдет, любые провайдеры TCP/IP будут автоматически закрыты.
Этот technote описывает методы, которые необходимо принять для разрешения с этими последствиями. Его основным вниманием является Mac OS X, несмотря на то, что он действительно охватывает традиционные проблемы Mac OS также. technote покрывает решения многих глюков размещения в разных сетях, различных методов для определения локального списка IP-адреса, как избежать набирать модем неожиданно, как обработать изменения, локальный список IP-адреса, и как говорить с собой с помощью петлевого IP-адреса.
BSD снабжает API сокетом на Mac OS X
Открыть библиотека совместимости Transport по Mac OS X
Открыть Transport API на традиционном Mac OS (включая внутреннюю Классику)
Это не обсуждает более старый TCP/IP APIs или их реализации, такие как МАКТКП или Открывает совместимость Transport's MacTCP. Интерфейс программирования МАКТКПА недостаточен для обработки всех случаев, описанных в этом примечании.
Этот technote также не покрывает высокоуровневый APIs, разделенный на уровни поверх этих ядро, объединяющее APIS В СЕТЬ. Для получения информации о том, как обработать динамические проблемы TCP/IP при использовании высокого уровня, сетевой API, такие как Доступ через URL и CFNetwork, видит документацию для определенного высокоуровневого API, который Вы используете.
Терминология
Mac OS поддерживает много сетевых APIs, и многие из того APIs имеют многократные реализации. Прежде чем мы сможем говорить специфические особенности, мы должны определить точно, что мы подразумеваем каждым сроком:
традиционный Mac OS — Все версии Mac OS до Mac OS X. Когда используется без квалификации это также включает Классику.
Mac OS X — Mac OS X 10.0 и позже.
Классика — Традиционное выполнение Mac OS в Классической среде совместимости на Mac OS X.
Mac OS — Все версии Mac OS, и включая традиционный Mac OS и включая Mac OS X.
МАКТКП API — Очень старый интерфейс программирования TCP/IP, поддерживаемый МАКТКПОМ и, Открывает Transport.
Откройте Transport API — основанный на XTI интерфейс программирования TCP/IP, представленный с, Открывает Transport. Этот API также поддерживается на Mac OS X, и в Классической среде совместимости и Основанной на углероде библиотекой совместимости.
Сокеты BSD — собственное сетевое программирование взаимодействует через интерфейс на Mac OS X. Это - стандарт сетевой API для UNIX. Необходимо использовать в своих интересах многочисленные документы не-Apple, касающиеся сокетов BSD, на некоторые из которых ссылаются ниже.
МАКТКП — Реализация МАКТКПА API на традиционном Mac OS до введения Открывает Transport.
Откройте Transport — сетевая среда для традиционного Mac OS, включая Классическую среду совместимости на Mac OS X. Откройте Transport был сначала представлен как часть Системы 7.5.2 на Power Mac 9500. Откройте Transport может быть установлен в системах, столь же старых как Система 7.1. Откройте Transport был сначала включен как часть стандартной установки в Системе 7.5.3. Откройте Transport был сетевым стеком по умолчанию для Mac OS 7.6 и все последующие версии традиционного Mac OS.
Совместимость МАКТКПА — Открывает, Transport предоставляет МАКТКПУ совместимость API для приложений, использующих МАКТКПА API.
Сети BSD — среда базовой сети для Mac OS X.
Откройте библиотеку совместимости Transport — Mac OS X включает библиотеку, обеспечивающую, Открывают совместимость Transport API для Основанных на углероде приложений.
Общий код
Многие примеры кода в этом technote полагаются на общие подпрограммы, показанные в Перечислении 1.
Подпрограммы утилиты Listing 1 Common
// Error Handling
// --------------
// SCF returns errors in two ways:
//
// o The function result is usually set to something
// generic (like NULL or false) to indicate an error.
//
// o There is a call, SCError, that returns the error
// code for the most recent function. These error codes
// are not in the OSStatus domain.
//
// We deal with this using two functions, MoreSCError
// and MoreSCErrorBoolean. Both of these take a generic
// failure indicator (a pointer or a Boolean) and, if
// that indicates an error, they call SCError to get the
// real error code. They also act as a bottleneck for
// mapping SC errors into the OSStatus domain, although
// I don't do that in this simple implementation.
//
// Note that I could have eliminated the failure indicator
// parameter and just called SCError but I'm worried
// about SCF returning an error indicator without setting
// the SCError. There's no justification for this worry
// other than general paranoia (I know of no examples where
// this happens),
static OSStatus MoreSCErrorBoolean(Boolean success)
{
OSStatus err;
int scErr;
err = noErr;
if ( ! success ) {
scErr = SCError();
if (scErr == kSCStatusOK) {
scErr = kSCStatusFailed;
}
// Return an SCF error directly as an OSStatus.
// That's a little cheesy. In a real program
// you might want to do some mapping from SCF
// errors to a range within the OSStatus range.
err = scErr;
}
return err;
}
static OSStatus MoreSCError(const void *value)
{
return MoreSCErrorBoolean(value != NULL);
}
static OSStatus CFQError(CFTypeRef cf)
// Maps Core Foundation error indications (such as they
// are) to the OSStatus domain.
{
OSStatus err;
err = noErr;
if (cf == NULL) {
err = coreFoundationUnknownErr;
}
return err;
}
static void CFQRelease(CFTypeRef cf)
// A version of CFRelease that's tolerant of NULL.
{
if (cf != NULL) {
CFRelease(cf);
}
} |
Два глюка размещения в разных сетях
Размещение в разных сетях является термином, использованным для описания компьютера больше чем с одним IP-адресом. В этом разделе описывается иметь дело с двумя общими глюками на многосетевых машинах. Эти методы релевантны и на традиционном Mac OS и на Mac OS X.
В Открывают Transport 1.3, и позже пользователь может сконфигурировать больше чем один IP-адрес на том же физическом интерфейсе (это известно как единственное размещение в разных сетях ссылки).
Можно включить многоканальное размещение в разных сетях с помощью стороннего программного обеспечения.
Когда компьютер рабочий сервер Удаленного доступа Apple получает входящий IPCP (TCP/IP по PPP) соединение, компьютерная прибыль второй IP-адрес.
Самое главное, однако, то, что все версии Mac OS X поддерживают размещение в разных сетях. Если Вы будете следовать инструкциям в этом разделе тогда, то Ваш код будет работать должным образом над обеими системами.
Размещение в разных сетях и связывает
Чтобы быть совместимым с размещением в разных сетях, Ваше программное обеспечение должно, в целом, связать с подстановочным IP-адресом (INADDR_ANY поскольку BSD снабжает код сокетом, kOTAnyInetAddress для Открывают код Transport), не к определенному IP-адресу. Для исходящих соединений это очень просто: поскольку BSD снабжает код сокетом, необходимо просто вызвать connect без вызова bind заранее, и для Открывают код Transport, необходимо связать конечную точку с помощью кода, показанного в Перечислении 2.
Перечисление 2 , Связывающее конечную точку для исходящих соединений
static OSStatus DoOutgoingBind(EndpointRef ep) { OSStatus err; err = OTBind(ep, NULL, NULL); return err; } |
запись слишком большого количества кода
создание программного обеспечения, которое не будет работать над многосетевой машиной, подключенной к несмежному Интернету
создание его тяжелее для обновления программного обеспечения для IPv6
Перечисление 3 показывает, как не связать конечную точку для исходящего соединения.
Перечисление 3 , Как не связать конечную точку для исходящих соединений
// ***** DO NOT DO THIS *****
static OSStatus DoOutgoingBindWrongly(EndpointRef ep)
{
OSStatus err;
InetInterfaceInfo info;
InetAddress primaryAddr;
TBind bindReq;
err = OTInetGetInterfaceInfo(&info, kDefaultInetInterface);
if (err == noErr) {
OTInitInetAddress(&primaryAddr, 0, info.fAddress);
OTMemzero(&bindReq, sizeof(bindReq));
bindReq.addr.buf = (UInt8 *) &primaryAddr;
bindReq.addr.len = sizeof(primaryAddr);
err = OTBind(ep, &bindReq, NULL);
}
return err;
}
// ***** DO NOT DO THIS ***** |
Для программного обеспечения, принимающего входящие соединения, ситуация очень подобна: в большинстве случаев необходимо связать с подстановочным IP-адресом (INADDR_ANY или kOTAnyInetAddress). Код, чтобы сделать это и для сокетов BSD и для Открыть Transport API показано в Перечислении 4.
Привязка перечисления 4 для входящих соединений
static int DoIncomingBindBSDSockets(int sock, u_short port)
{
int err;
struct sockaddr_in req;
memset(&req, 0, sizeof(req));
req.sin_family = AF_INET;
req.sin_addr.s_addr = htonl(INADDR_ANY);
req.sin_port = htons(port);
err = bind(sock, (struct sockaddr *) &req, sizeof(req));
if (err == -1) {
err = errno;
}
return err;
}
static OSStatus DoIncomingBindOT(EndpointRef ep, InetPort port)
{
OSStatus err;
TBind req;
TBind ret;
InetAddress reqAddr;
InetAddress retAddr;
OTInitInetAddress(&reqAddr, port, kOTAnyInetAddress);
OTMemzero(&req, sizeof(req));
req.addr.buf = (UInt8 *) &reqAddr;
req.addr.len = sizeof(reqAddr);
req.qlen = 10;
OTMemzero(&ret, sizeof(ret));
ret.addr.buf = (UInt8 *) &retAddr;
ret.addr.maxlen = sizeof(retAddr);
err = OTBind(ep, &req, &ret);
if (err == noErr) {
if (retAddr.fPort != reqAddr.fPort) {
(void) OTUnbind(ep);
err = kOTAddressBusyErr;
}
}
return err;
} |
При некоторых обстоятельствах для программного обеспечения сервера полезно связать с определенным IP-адресом. Например, веб-сервер мог бы сделать это так, он может возвратить различные веб-страницы в зависимости от адреса, с которым соединился клиент. Пример кода DTS OTSimpleServerHTTP иллюстрирует этот метод. Однако, если Вы не должны отвечать по-другому на различных IP-адресах, корректная вещь сделать состоит в том, чтобы связать Ваш сервер с подстановочным IP-адресом.
Размещение в разных сетях и FTP
На многоканальном многоадресном компьютере для «корректного» локального IP-адреса компьютера возможно зависеть от IP-адреса узла, с которым Вы связываетесь.
Например, рассмотрите компьютер с двумя платами Ethernet, одним соединенным к общедоступному Интернету и одним соединенным к частной сети. Каждая карта имеет IP-адрес, но машина не передает пакеты IP между картами. Эта ситуация является проиллюстрированным рисунком 1.

Теперь рассмотрите клиент FTP, работающий на этом компьютере. Один из (ми), которые функции протокола FTP - то, что, когда это открывает информационное соединение, клиент FTP должен открыть порт на локальной машине и отправить (через соединение управления) номер порта и локальный IP-адрес к серверу в команде PORT. Однако машины в общедоступном Интернете могут только связаться с 17.100.55.7, и машины на частной сети могут только связаться с 17.200.37.41. Таким образом, как делает работу с клиентами FTP который IP-адрес отправить?
Ответ - то, что каждый сетевой API имеет функцию, возвращающую источник локальный IP-адрес для соединения. Поскольку BSD снабжает сокетом, это getsockname и для Открыть Transport API это OTGetProtAddress. Таким образом, клиент FTP может вызвать одну из этих функций на соединении управления для определения корректного локального адреса для использования для информационного соединения.
Код в Перечислении 5 показывает, как получить локальный адрес для соединения с помощью и сокетов BSD и Открыть Transport API.
Перечисление 5 , Получающее локальный IP-адрес для соединения
static int GetLocalIPAddressForConnectionBSDSockets(int sock,
struct in_addr *localAddr)
{
int err;
int len;
struct sockaddr_in local;
len = sizeof(local);
err = getsockname(sock, (struct sockaddr *) &local, &len);
if (err == -1) {
err = errno;
}
if (err == 0) {
assert(len == sizeof(local));
*localAddr = local.sin_addr;
}
return err;
}
static OSStatus GetLocalIPAddressForConnectionOT(EndpointRef ep,
InetAddress *localAddr)
{
OSStatus err;
TBind localBind;
// only works if endpoint connected
assert(OTGetEndpointState(ep) == T_DATAXFER);
assert(OTIsBlocking(ep));
OTMemzero(&localBind, sizeof(TBind));
localBind.addr.buf = (UInt8 *) localAddr;
localBind.addr.maxlen = sizeof(InetAddress);
err = OTGetProtAddress(ep, &localBind, NULL);
return err;
} |
Вызов всего IPs
В этом разделе описывается можно получить список всех IP-адресов на машине и быть уведомлены, когда изменяется тот список.
Вы пишете сервер, отвечающий по-другому, в зависимости от которого IP-адреса клиент соединяется с.
Вы выводите на экран список IP-адресов пользователю.
При использовании этого кода по какой-либо другой причине, необходимо тщательно рассмотреть проблемы совместимости размещения в разных сетях перед продолжением.
Если Вы пишете сервер, отвечающий по-другому, в зависимости от которого IP-адреса клиент соединяется с, необходимо также считать Этикет Сервера.
Получение списка всех IP-адресов
Существует по крайней мере три различных метода для получения списка всех IP-адресов машины (локальный список IP-адреса):
Платформа Конфигурации системы
Откройте Transport API
Сокеты BSD
Следующие разделы описывают каждый из этих методов поочередно. Выбор которого метод использовать зависит от системных требований и существующей структуры Вашего кода:
Если Вам нужен метод, работающий над традиционным Mac OS, необходимо использовать Открыть Transport API. Можно тогда принять решение использовать тот же код Mac OS X или записать новый код для Mac OS X, использующего платформу Конфигурации системы.
Если Вы хотите совместно использовать исходный код с другими платформами UNIX, подход сокетов BSD является, вероятно, лучшим.
Если Вы пишете код исключительно для Mac OS X, и Вы должны быть уведомлены, когда список IP локальные изменения адресов, платформа Конфигурации системы является лучшим подходом.
При прочих равных условиях Apple рекомендует подход Платформы конфигурации системы (SCF) по подходу сокетов BSD потому что
Когда список изменяется, и, SCF обеспечивает способ уведомить Вас
SCF изолирует Вас от изменений в ядре базовой сети.
Платформа конфигурации системы
Mac OS X 10.1 представил общедоступный API, Платформу конфигурации системы (SCF), для доступа к настройке сети и информации состояния. SCF является рекомендуемым способом для Вас получить локальный список IP-адреса под Mac OS X. Перечисление 6 показывает, как можно сделать это.
Перечисление 6 , Добирающееся локальный список IP-адреса с помощью платформы Конфигурации системы
static void GetIPAddressListFromValue(const void *key,
const void *value,
void *context)
// This function is a callback CopyIPAddressListSCF when
// it calls CFDictionaryApplyFunction. It extracts the
// IPv4 address list from the network service dictionary
// and appends it to the result dictionary (which is passed
// in via the context pointers).
{
CFArrayRef intfAddrList;
assert( key != NULL );
assert( CFGetTypeID(key) == CFStringGetTypeID() );
assert( value != NULL );
assert( CFGetTypeID(value) == CFDictionaryGetTypeID() );
assert( context != NULL );
assert( CFGetTypeID(context) == CFArrayGetTypeID() );
intfAddrList = CFDictionaryGetValue(value,
kSCPropNetIPv4Addresses);
if (intfAddrList != NULL) {
assert( CFGetTypeID(intfAddrList)
== CFArrayGetTypeID() );
CFArrayAppendArray(context,
intfAddrList,
CFRangeMake(0, CFArrayGetCount(intfAddrList))
);
}
}
static OSStatus CopyIPAddressListSCF(CFArrayRef *addrList)
// Returns a CFArray that contains every IPv4
// address on the system (as CFStrings) in no
// particular order.
{
OSStatus err;
SCDynamicStoreRef ref;
CFStringRef pattern;
CFArrayRef patternList;
CFDictionaryRef valueDict;
CFMutableArrayRef result;
assert( addrList != NULL);
assert(*addrList == NULL);
ref = NULL;
pattern = NULL;
patternList = NULL;
valueDict = NULL;
result = NULL;
// Create a connection to the dynamic store, then create
// a search pattern that finds all IPv4 entities.
// The pattern is "State:/Network/Service/[^/]+/IPv4".
ref = SCDynamicStoreCreate( NULL,
CFSTR("CopyIPAddressListSCF"),
NULL,
NULL);
err = MoreSCError(ref);
if (err == noErr) {
pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(
NULL,
kSCDynamicStoreDomainState,
kSCCompAnyRegex,
kSCEntNetIPv4);
err = MoreSCError(pattern);
}
// Now make a pattern list out of the pattern and then
// call SCDynamicStoreCopyMultiple. We use that call,
// rather than repeated calls to SCDynamicStoreCopyValue,
// because it gives us a snapshot of the state.
if (err == noErr) {
patternList = CFArrayCreate(NULL,
(const void **) &pattern,
1,
&kCFTypeArrayCallBacks);
err = CFQError(patternList);
}
if (err == noErr) {
valueDict = SCDynamicStoreCopyMultiple(ref,
NULL,
patternList);
err = MoreSCError(valueDict);
}
// For each IPv4 entity that we found, extract the list
// of IP addresses and append it to our results array.
if (err == noErr) {
result = CFArrayCreateMutable(NULL, 0,
&kCFTypeArrayCallBacks);
err = CFQError(result);
}
// Iterate over the values, extracting the IP address
// arrays and appending them to the result.
if (err == noErr) {
CFDictionaryApplyFunction(valueDict,
GetIPAddressListFromValue,
result);
}
// Clean up.
CFQRelease(ref);
CFQRelease(pattern);
CFQRelease(patternList);
if (err != noErr && result != NULL) {
CFQRelease(result);
result = NULL;
}
*addrList = result;
assert( (err == noErr) == (*addrList != NULL) );
return err;
} |
Откройте Transport API
Код в Перечислении 7 показывает, как решить, что локальное использование списка IP-адреса Открывает вызовы Transport. Этот код будет работать и над традиционным Mac OS и над Mac OS X. Если Ваша программа работает на традиционном Mac OS, это - код для использования. Если Ваш код кода также работает на Mac OS X, можно продолжать использовать этот код, несмотря на то, что Apple рекомендует использовать платформу Конфигурации системы, потому что это обеспечивает способ уведомить Вас, когда изменяется список.
Перечисление 7 , Получающее локальное использование списка IP-адреса, Открывает Transport
typedef InetHost **InetHostHandle;
static OSStatus AddSecondaryAddresses(
InetInterfaceInfo* interfaceInfo,
SInt32 interfaceIndex,
InetHostHandle addrList)
{
OSStatus err;
InetHost *addrBuf;
UInt32 addrCount;
addrBuf = NULL;
addrCount = interfaceInfo->fIPSecondaryCount;
// Allocate a buffer for the secondary address info.
addrBuf = (InetHost *) NewPtr(addrCount * sizeof(InetHost));
if (addrBuf == NULL) {
err = kENOMEMErr;
}
// Ask OT for the list of secondary addresses on this
// interface and add each secondary address to the list.
if (err == noErr) {
err = OTInetGetSecondaryAddresses(addrBuf,
&addrCount,
interfaceIndex);
}
if (err == noErr) {
err = PtrAndHand(addrBuf,
(Handle) addrList,
addrCount * sizeof(InetHost));
}
// Clean up.
if (addrBuf != NULL) {
DisposePtr( (Ptr) addrBuf );
}
return err;
}
enum
{
kOTIPSingleLinkMultihomingVersion = 0x01300000
};
static OSStatus GetIPAddressListOT(InetHostHandle addrList)
{
OSStatus err;
Boolean haveIPSingleLinkMultihoming;
NumVersionVariant otVersion;
SInt32 interfaceIndex;
InetInterfaceInfo info;
Boolean done;
// Must be running at system task time.
assert( TaskLevel() == 0 );
SetHandleSize( (Handle) addrList, 0 );
assert( MemError() == noErr );
haveIPSingleLinkMultihoming =
( Gestalt(gestaltOpenTptVersions, (long *) &otVersion) == noErr
&& (otVersion.whole >= kOTIPSingleLinkMultihomingVersion )
&& ( OTInetGetSecondaryAddresses
!= (void *) kUnresolvedCFragSymbolAddress));
err = noErr;
done = false;
interfaceIndex = 0;
do {
done = ( OTInetGetInterfaceInfo(&info, interfaceIndex) != noErr );
if ( ! done ) {
// If all interfaces are disabled Mac OS X
// returns a single interface with a 0
// address, so we specifically exclude that.
// Otherwise just add the IP address of this
// interface to the list.
if (info.fAddress != kOTAnyInetAddress) {
err = PtrAndHand(&info.fAddress,
(Handle) addrList,
sizeof(InetHost));
}
// Now add any secondary addresses.
if ( err == noErr
&& haveIPSingleLinkMultihoming
&& info.fIPSecondaryCount > 0 ) {
err = AddSecondaryAddresses(&info,
interfaceIndex,
addrList);
}
interfaceIndex += 1;
}
} while (err == noErr && !done);
return err;
} |
Сокеты BSD
Mac OS 10.2 и более поздняя поддержка новый вызов, getifaddrs, это возвращает список сетевых интерфейсов и их присвоенных адресов. Это - самый простой способ получить локальный список IP-адреса с помощью стиля BSD APIs. Однако это только работает над Mac OS X 10.2 и позже. В более ранних системах необходимо вырыть немного глубже.
Сокеты BSD API обеспечивают ioctl, SIOCGIFCONF, это возвращает список всех интерфейсов в системе. Можно использовать этот ioctl для получения локального списка IP-адреса. Пример выполнения этого get_ifi_info подпрограмма на странице 434 Сетевого программирования UNIX. Можно даже загрузить исходный код с веб-страницы книги. Если мобильность на другие платформы UNIX является требованием, этот метод полезен на Mac OS X 10.1.x и ранее, и.
Когда разлагается хороший IPs
При кэшировании локального списка IP-адреса (или неявно, путем открытия слушателя для каждого локального IP-адреса, или явно в коде), необходимо реализовать механизм для обновления кэша, когда изменяется список. Лучший способ сделать это зависит от Вашей целевой платформы: методы и для Mac OS X и для традиционного Mac OS описаны ниже. Если у Вас будет приложение Углерода, работающее на обеих платформах, то необходимо будет, вероятно, использовать оба метода.
Mac OS X
На Mac OS X лучший путь, который будет уведомлен относительно изменений в локальном списке IP-адреса, состоит в том, чтобы запросить уведомления от платформы Конфигурации системы. Перечисление 8 показывает, как установить это. Эта функция создает соединение с динамической памятью платформы Конфигурации системы и соответствующим источником цикла выполнения. Если Вы добавляете (использование CFRunLoopAddSource) этот источник цикла выполнения к Вашему циклу выполнения (обычно найденный с CFRunLoopGetCurrent), безотносительно функции Вы предоставили к CreateIPAddressListChangeCallbackSCF будет вызван, когда любые объекты IPv4 изменяются в динамической памяти платформы Конфигурации системы, т.е. когда изменяется локальный список IP-адреса.
Перечисление 8 Используя платформу Конфигурации системы для IP-адреса изменяет уведомление
static OSStatus CreateIPAddressListChangeCallbackSCF(
SCDynamicStoreCallBack callback,
void *contextPtr,
SCDynamicStoreRef *storeRef,
CFRunLoopSourceRef *sourceRef)
// Create a SCF dynamic store reference and a
// corresponding CFRunLoop source. If you add the
// run loop source to your run loop then the supplied
// callback function will be called when local IP
// address list changes.
{
OSStatus err;
SCDynamicStoreContext context = {0, NULL, NULL, NULL, NULL};
SCDynamicStoreRef ref;
CFStringRef pattern;
CFArrayRef patternList;
CFRunLoopSourceRef rls;
assert(callback != NULL);
assert( storeRef != NULL);
assert(*storeRef == NULL);
assert( sourceRef != NULL);
assert(*sourceRef == NULL);
ref = NULL;
pattern = NULL;
patternList = NULL;
rls = NULL;
// Create a connection to the dynamic store, then create
// a search pattern that finds all IPv4 entities.
// The pattern is "State:/Network/Service/[^/]+/IPv4".
context.info = contextPtr;
ref = SCDynamicStoreCreate( NULL,
CFSTR("AddIPAddressListChangeCallbackSCF"),
callback,
&context);
err = MoreSCError(ref);
if (err == noErr) {
pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(
NULL,
kSCDynamicStoreDomainState,
kSCCompAnyRegex,
kSCEntNetIPv4);
err = MoreSCError(pattern);
}
// Create a pattern list containing just one pattern,
// then tell SCF that we want to watch changes in keys
// that match that pattern list, then create our run loop
// source.
if (err == noErr) {
patternList = CFArrayCreate(NULL,
(const void **) &pattern, 1,
&kCFTypeArrayCallBacks);
err = CFQError(patternList);
}
if (err == noErr) {
err = MoreSCErrorBoolean(
SCDynamicStoreSetNotificationKeys(
ref,
NULL,
patternList)
);
}
if (err == noErr) {
rls = SCDynamicStoreCreateRunLoopSource(NULL, ref, 0);
err = MoreSCError(rls);
}
// Clean up.
CFQRelease(pattern);
CFQRelease(patternList);
if (err != noErr) {
CFQRelease(ref);
ref = NULL;
}
*storeRef = ref;
*sourceRef = rls;
assert( (err == noErr) == (*storeRef != NULL) );
assert( (err == noErr) == (*sourceRef != NULL) );
return err;
} |
Традиционный Mac OS
На традиционном Mac OS лучший метод для наблюдения за изменениями в локальном списке IP-адреса варьируется в зависимости от версии, Открывают Transport. Откройте Transport 2.5, и выше (настоящее начиная с Mac OS 9) поставит события перехода штабеля TCP/IP notifier Вашего приложения (зарегистрированное использование OTRegisterAsClient). Можно установить notifier и прислушаться kOTStackWasLoaded событие, после которого можно создать локальный список IP-адреса, как описано ранее.
Более ранние версии Открывают, Transport не отправляют эти события перехода штабеля. Единственный хороший способ обнаружить изменения в локальном списке IP-адреса состоит в том, чтобы периодически опрашивать список.
Никакие злонамеренные вызовы,
Mac OS позволяет пользователю конфигурировать их компьютер для набора номера по требованию через флажок в панели управления сетью («Подключение автоматически при запущении приложений TCP/IP»). Ваше программное обеспечение должно бояться случайно набирать модем, когда пользователь не ожидал его. Лучший способ сделать это зависит от целевой платформы. Прежде чем мы начнем обсуждать эти методы подробно, однако, мы должны определить некоторые условия.
Терминология
Ради этого обсуждения полезно определить два класса сетевой активности. Требуемая сетевая операция является результатом прямой пользовательской команды. Требуемые операции должны инициировать набор по требованию при необходимости. Например, если пользователь откроет веб-страницу в браузере, или проверит на электронную почту или начнет загружать файл, то они ожидают, что модем наберет при необходимости.
Напротив, незапрашиваемая сетевая операция только косвенно связана с пользовательским действием и не должна инициировать набор по требованию. Например, автоматическая функция обновления программного обеспечения Вашего приложения является почти наверняка незапрашиваемой работой; если Ваше программное обеспечение наберет их модем только для проверки на обновления программного обеспечения, будет раздражаться большинство пользователей.
Один полезный метод должен выполнить незапрашиваемые операции паразитирующе; когда пользователь соединяется с сетью по другим причинам, Ваше программное обеспечение должно использовать в своих интересах сетевое соединение и выполнить любые незаконченные незапрашиваемые операции. Например, программа почтового сервера могла контролировать состояние сети и принять решение проверить на и поставить почту, как только пользователь установил соединение по другим причинам. Можно наблюдать за изменениями в сетевом соединении с помощью методов, описанных ранее.
Рассмотрите пример автоматической программы обновления программного обеспечения, находящейся в фоновом режиме, ожидая компьютера для соединения с сетью. Когда это происходит, это быстро и автоматически проверяет на присутствие обновления программного обеспечения. Однако это не должно начинать загружать архив мультимегабайта, не спрашивая пользователя сначала, иначе трафик, связанный с этой незапрашиваемой работой, предотвратит неактивное разъединение.
Во многих случаях классификация работы, как требуется или незапрашиваемый является личным выбором. Для продолжения предыдущего примера приложение почтового сервера могло сохранить почту локально и попытаться паразитирующе поставить его. Однако, если пользователь не устанавливает соединение в течение разумного срока (скажите день), почтовый сервер должен, вероятно, соединиться так или иначе. В конечном счете необходимо решить, как управлять этими ситуациями в зависимости от конкретного случая, и затем принять обратную связь от пользователей. Можно даже хотеть обеспечить пользовательскую настройку для управления этим поведением.
Наконец, стоит отметить, что методы обсудили ниже только работы, если модем непосредственно подключен к компьютеру. Если связь компьютера косвенно выполняется через модем (например, компьютер находится в сети аэропорта отправления и подключениях Базовой станции AirPort к Интернету через его модем), существует очень мало, можно сделать для предотвращения злонамеренных вызовов.
Mac OS X
Mac OS X предоставляет определенную поддержку для предотвращения злонамеренных вызовов. Платформа Конфигурации системы экспортирует две функции, SCNetworkCheckReachabilityByAddress и SCNetworkCheckReachabilityByName, которые определяют, инициирует ли связь с определенным сайтом модем для набора номера. Прежде, чем сделать любую незапрашиваемую сетевую операцию необходимо вызвать эти функции, чтобы видеть, могли ли бы Вы раздражать пользователя путем набора номера модема. Перечисление 9 показывает пример того, как сделать это.
Перечисление 9 Используя платформу Конфигурации системы для проверки достижимости
static Boolean UnsolicitedAllowedSCF(const char *serverName)
{
Boolean result;
SCNetworkConnectionFlags flags;
// IMPORTANT:
// To work with CodeWarrior you should set the
// "enums are always int" option, which the CWPro8
// Mach-O stationery fails to do.
assert(sizeof(SCNetworkConnectionFlags) == sizeof(int));
result = false;
if ( SCNetworkCheckReachabilityByName(serverName, &flags) ) {
result = !(flags & kSCNetworkFlagsConnectionRequired)
&& (flags & kSCNetworkFlagsReachable);
}
return result;
} |
Одно основное отличие между традиционным Mac OS и Mac OS X - то, что Mac OS X реализует набор по требованию путем контроля трафика, тогда как традиционный Mac OS набирает модем при открытии провайдера TCP/IP. Поэтому на Mac OS X, необходимо проверить на сетевую достижимость перед передачей, тогда как на традиционном Mac OS необходимо проверить на сетевую достижимость прежде, чем открытие провайдера TCP/IP. Ситуация с традиционным Mac OS объяснена более подробно ниже.
Традиционный Mac OS
При работе традиционного Mac OS программное обеспечение должно стараться создать провайдера TCP/IP только, когда это фактически должно использовать сеть. Даже если Вы не отправляете сетевого трафика, это вызвано тем, что действие Вас открытие провайдера TCP/IP может заставить модем набирать.
Ваше приложение может избежать набирать модем для незапрашиваемых операций путем простого вызова OTInetGetInterfaceInfo прежде, чем запустить сетевую операцию. Если OTInetGetInterfaceInfo указывает, что штабель TCP/IP загружается, модем (если таковые имеются) был уже набран, и Ваше приложение может безопасно использовать сеть. Перечисление 10 показывает, как сделать это.
Перечисление 10 Используя OTInetGetInterfaceInfo для проверки достижимости
static Boolean UnsolicitedAllowedTrad(const char *serverName)
{
#pragma unused(serverName)
InetInterfaceInfo info;
return ( OTInetGetInterfaceInfo(&info,
kDefaultInetInterface) == noErr );
} |
В то время как вышеупомянутый код очень прост, некоторые разработчики сочли его недостаточно строгим для их вкуса. Например, штабель TCP/IP мог бы быть разгружен, но машина подключается через Ethernet, так открытие провайдера TCP/IP вряд ли причинит беспокойство пользователю. Более строгий подход показан в Перечислении 11. Это использует NSHTCPWillDial (от примера кода DTS «MoreNetworkSetup») для проверки на достижимость. Это имеет преимущество, что оно покрывает больше случаев, за счет делают код значительно более сложным (как только Вы начинаете смотреть в реализации NSHTCPWillDial).
Перечисление 11 Используя NSHTCPWillDial для проверки достижимости
static Boolean UnsolicitedAllowedMNS(const char *serverName)
{
#pragma unused(serverName)
UInt32 willDial;
return (NSHTCPWillDial(&willDial) == noErr)
&& (willDial == kNSHTCPDialNo);
} |
Случай относительно редок. Большинство пользователей соединяет ссылку PPP с помощью набора по требованию, что означает, что штабель TCP/IP загружается, когда соединяется ссылка.
Обнаружение состояния канала PPP должно быть сделано со специфичным для ссылки кодом. В то время как было бы относительно просто покрыть некоторые общие падежи (ARA, FreePPP и деривативы), не будет никакого конца списку особых случаев для покрытия, и некоторые из тех случаев и распространены и хитры (AOL).
NSHTCPWillDial производит ложное отрицание, которое является наименее неудобным отказом для пользователя.
Выход из строя конечной точки
Существует много ситуаций, где штабель TCP/IP вынужден лишить законной силы некоторые Ваши соединения неожиданно. В этом разделе описывается, как это может произойти и как можно обнаружить и исправить проблему.
Выход из строя конечной точки на Mac OS X
Штабель TCP/IP на Mac OS X всегда загружается. Это предотвращает много проблем, происходящих на традиционном Mac OS. Например, Mac OS X всегда позволяет приложениям TCP/IP говорить с другими приложениями на той же машине (см. Говорящий с Собой), и никогда не закрывается, Открывают провайдеров Transport для Вас. Однако, когда локальный список IP-адреса изменяется, для исходного адреса соединения возможно исчезнуть из списка. Это создает устаревшее соединение, эффективно повреждающееся то. К сожалению, Ваше приложение не уведомляется относительно этого. В частности Вы могли бы ожидать, что соединение TCP повредится (например, асинхронная конечная точка OT получит a T_DISCONNECT событие), но это не происходит. Вместо этого соединение продолжает существовать, но не будет в состоянии отправить или получить любые данные.
Эта проблема является основным принципом самого протокола TCP/IP и влияет и на сокеты BSD, и Откройте конечные точки Transport. Если его локальный адрес больше не находится в локальном списке IP-адреса, соединение является устаревшим. Обычно затронутые соединения:
связанные сокеты TCP и конечные точки
подключенные сокеты UDP
несвязанный TCP и сокеты UDP и конечные точки, связывающиеся с определенным IP-адресом (а не подстановочным IP-адресом)
Ваша стратегия контакта с устаревшими соединениями будет зависеть от природы Вашего приложения. Для клиентских приложений, где соединения являются обычно недолгими, Вы, вероятно, ничего не должны делать. При реализации механизма тайм-аута, общее отсутствие любых данных, переданных на соединении, в конечном счете инициирует тайм-аут, и Вы закроете соединение. Также пользователь может принять решение вручную закрыть соединение.
Для клиентских приложений с долгосрочными соединениями необходимо реализовать своего рода гарантию против устаревших соединений. Один метод для того, чтобы сделать это должен наблюдать за изменениями в локальном списке IP-адреса (использующий платформу Конфигурации системы, как описано выше) и, после каждого изменения, проверить, что исходный адрес каждого из Ваших соединений (который можно получить использование кода, показанного ранее) находится все еще в локальном списке IP-адреса. Если исходный адрес соединения больше не находится в локальном списке IP-адреса, соединение является устаревшим, и необходимо восстановить его (подвергающийся любым соображениям злонамеренного вызова). Перечисление 12 показывает, как проверить на устаревшие соединения и под сокетами BSD и под Открыть Transport API.
Перечисление 12 , Проверяющее, является ли соединение устаревшим
static Boolean IsEndpointStale(EndpointRef ep,
InetHostHandle addrList)
{
Boolean stale;
InetAddress sourceAddr;
ItemCount index;
ItemCount count;
if ( GetLocalIPAddressForConnectionOT(ep,
&sourceAddr) != noErr ) {
stale = true;
} else {
assert(sourceAddr.fAddressType == AF_INET);
if (sourceAddr.fHost == kOTAnyInetAddress) {
stale = false;
} else {
stale = true;
count = GetHandleSize( (Handle) addrList ) / sizeof(InetHost);
for (index = 0; index < count; index++) {
if ( sourceAddr.fHost == (*addrList)[index] ) {
stale = false;
break;
}
}
}
}
return stale;
}
static Boolean IsSocketStale(int sock, CFArrayRef addrList)
{
Boolean stale;
struct in_addr sourceAddr;
CFStringRef sourceAddrStr;
sourceAddrStr = NULL;
if ( GetLocalIPAddressForConnectionBSDSockets(
sock,
&sourceAddr) != 0 ) {
stale = true;
} else {
if (sourceAddr.s_addr == INADDR_ANY) {
stale = false;
} else {
stale = true;
sourceAddrStr = CFStringCreateWithCString(
NULL,
inet_ntoa(sourceAddr),
kCFStringEncodingASCII);
if (sourceAddrStr != NULL) {
stale = ! CFArrayContainsValue(
addrList,
CFRangeMake(0, CFArrayGetCount(addrList)),
sourceAddrStr);
}
}
}
CFQRelease(sourceAddrStr);
return stale;
} |
Для серверных приложений необходимо последовать совету в Этикете Сервера.
Выход из строя конечной точки на традиционном Mac OS
Жизненный цикл штабеля TCP/IP на традиционном Mac OS намного более сложен. Ключевой аспект Открывает, Transport - то, что штабель TCP/IP может загрузиться и разгрузиться из памяти. Когда штабель разгружен, Вы не можете использовать службы TCP/IP. Если Вы создаете провайдера TCP/IP, Открываете, Transport загружает штабель TCP/IP. Если компьютер будет сконфигурирован для набора номера по требованию, то загрузка штабеля TCP/IP инициирует модем для набора номера. Если модемное соединение перестанет работать, то штабель TCP/IP не загрузится и, если это было инициировано Вами создающий провайдера, функция создания провайдера возвратит ошибку.
Методы для избегают набора по требованию, проблемы не обсуждены ни в Каких Злонамеренных вызовах.
Штабель TCP/IP может разгрузиться из памяти при многих обстоятельствах:
если TCP/IP использует модем и модемные разъединения
если IP-адрес машины изменяется (например, DHCP не мог бы возобновить арендный договор),
если компьютер помещается в сон (за исключением отмеченного ниже)
если пользователь изменяет настройки в панели управления TCP/IP
если некоторое приложение передает изменения в параметрах сети с помощью Настройки сети
более старые версии Открывают, Transport может разгрузить штабель TCP/IP после двух минут, если закрываются все провайдеры
Когда штабель TCP/IP разгружается, он закрывает всех провайдеров TCP/IP. Когда это закрывает провайдера таким образом, Откройте, Transport вызывает notifier провайдера с одним из двух событий.
kOTProviderWillCloseотправляется, когда OT закрывает Вашего провайдера управляемым способом, обычно когда пользователь реконфигурировал штабель TCP/IP. В системное время задачи это всегда отправляется. Можно принять решение поместить провайдера в синхронный режим и закрыть сетевое соединение чисто.kOTProviderHasClosedкогда OT «вызывают завершения» Ваш провайдер, отправляется. Когда базовый канальный уровень закрывается, это обычно делается. Это может быть отправлено в системной задаче или задержанное время задачи, таким образом, необходимо записать код, чтобы предположить, что это работает в задержанное время задачи. Базовый провайдер был уже закрыт, но необходимо вызватьOTCloseProviderизбегать (маленькой) утечки памяти.
Когда Вы возвратитесь из своего notifier, независимо от действия Вашего notifier будет всегда закрываться провайдер. Любые операции на провайдере после Ваших возвратов notifier возвратятся kOTBadReferenceErr.
Для провайдеров TCP/IP, над которыми Вы активно работаете (например, конечные точки работника, активно передающие данные), можно проигнорировать эти события. В следующий раз, когда Вы используете провайдера, Вы получите a kOTBadReferenceErr ошибка, на которую должна ответить Ваша универсальная обработка ошибок путем закрытия провайдера. Однако при открытии провайдера TCP/IP, который Вы активно не продолжаете работать (такой InetSvcRef который Вы периодически используете для поисков DNS или конечной точки слушания в сервере), необходимо установить notifier, обрабатывающий эти события. Перечисление 13 является примером того, как сделать это.
Перечисление 13 , Обрабатывающее провайдера, закрыло события
static InetSvcRef gInetServices = kOTInvalidProviderRef;
static pascal void MyInetServicesNotifier(
void* contextPtr,
OTEventCode code,
OTResult result,
void* cookie)
{
#pragma unused(contextPtr)
#pragma unused(result)
#pragma unused(cookie)
switch (code) {
case kOTSyncIdleEvent:
// [... yielding code removed ...]
break;
case kOTProviderWillClose:
case kOTProviderIsClosed:
// OT is closing the provider out from underneath us.
// We remove our reference to it so the next time
// someone calls MyStringToAddress, we'll reopen it.
(void) OTCloseProvider(gInetServices);
gInetServices = kOTInvalidProviderRef;
break;
default:
// do nothing
break;
}
}
static OSStatus MyOpenInetServices(void)
{
OSStatus err;
OSStatus junk;
gInetServices = OTOpenInternetServicesInContext(
kDefaultInternetServicesPath, 0, &err, NULL);
if (err == noErr) {
junk = OTSetBlocking(gInetServices);
assert(junk == noErr);
junk = OTSetSynchronous(gInetServices);
assert(junk == noErr);
junk = OTInstallNotifier(gInetServices,
MyInetServicesNotifier, NULL);
junk = OTUseSyncIdleEvents(gInetServices, true);
assert(junk == noErr);
}
return err;
}
static OSStatus MyStringToAddress(const char *string,
InetHost *address)
{
OSStatus err;
InetHostInfo hostInfo;
// If the DNS provider isn't currently open, open it.
err = noErr;
if (gInetServices == kOTInvalidProviderRef) {
err = MyOpenInetServices();
}
// Now do the name to address translation using the provider.
if (err == noErr) {
err = OTInetStringToAddress(gInetServices,
(char *) string, &hostInfo);
}
if (err == noErr) {
// For this example, we just return the host's first
// IP address.
*address = hostInfo.addrs[0];
}
return err;
} |
Перечисление 13 иллюстрирует два важных тезиса:
gInetServicesпровайдер не создается, пока программа не должна преобразовывать имя к адресу. Это ленивое создание предотвращает программу, набирая модем преждевременно.Когда notifier сообщают, что провайдер закрылся, это лишает законной силы
gInetServices. В следующий разMyStringToAddressвызывается, это заметит это и воссоздаст провайдера.
Поскольку Открывают, Transport всегда закрывает любых провайдеров прежде, чем изменить локальный список IP-адреса, не возможно получить устаревшие соединения на традиционном Mac OS.
Этикет сервера
Обработка событий, описанных в предыдущем разделе, особенно важна для серверов. Сервер будет обычно иметь один или несколько открытые слушатели (слушающий сокеты для кода сокетов BSD, или конечные точки слушания для Открывают код Transport), которые ожидают соединений от клиентов. Важно, чтобы те слушатели остались активными независимо от сетевых реконфигурирований.
Слушатели на Mac OS X
Если Вы следуете совету, данному ранее, обработка слушателей на Mac OS X очень проста. Штабель TCP/IP на Mac OS X никогда не разгружается, таким образом, никогда не будут автоматически закрываться Ваши слушатели. Кроме того, потому что Ваши слушатели связываются с подстановочным IP-адресом (INADDR_ANY поскольку BSD снабжает код сокетом, kOTAnyInetAddress для Открывают код Transport), изменения в локальном списке IP-адреса никогда не будут создавать устаревшего слушателя.
При привязке слушателя определенного IP-адреса (единственное серьезное основание для того, чтобы сделать, это - то, так, чтобы сервер мог вести себя по-другому, в зависимости от какого IP-адреса клиент соединяется с), необходимо наблюдать за изменениями в локальном списке IP-адреса. Если IP-адрес исчезает из списка, необходимо закрыть его слушателя. Если новый IP-адрес обнаруживается в списке, необходимо открыть нового слушателя для того IP-адреса. Также при обнаружении какого-либо изменения в локальном списке IP-адреса, можно просто закрыть всех слушателей и перезапустить их на основе нового списка IP-адреса.
Эти рекомендации применяются независимо от того, используете ли Вы сокеты BSD или Открыть Transport API.
Слушатели на традиционном Mac OS
Если Ваш сервер будет иметь открытых слушателей, и штабель TCP/IP разгружается, то те слушатели закроются, и Ваш notifier получит событие с этой целью. Если Вы не обрабатываете эти события должным образом, возможности состоят в том, что Ваш сервер продолжит работать очень хорошо, кроме него не получит больше T_LISTEN события и будут «глухими» к его клиентам.
Стандартный ответ на закрытие слушателя должен просто вновь открыть слушателя. Вы не должны пытаться сделать это непосредственно в Вашем notifier. Вместо этого необходимо установить флаг, заставляющий основной цикл событий вновь открывать слушателя, как только загрузился TCP/IP. Можно определить это путем проверки результата OTInetGetInterfaceInfo, как описано ни в Каких Злонамеренных вызовах.
Как правило, открытие слушателя является незапрашиваемой работой и должно быть задержано, если оно заставило бы модем набирать. Если Ваше приложение, вероятно, будет использоваться в среде, где оно должно набрать модем для открытия слушателя, можно хотеть обеспечить пользовательскую настройку для этого. Пример показан ниже. Обычно право преимущественной покупки было бы значением по умолчанию.

Говоря с собой
Говор с собой может быть первым знаком безумия, но программное обеспечение TCP/IP часто хочет говорить с другим программным обеспечением, работающим на той же машине. Например, у Вас мог бы быть инструмент администрирования сервера, конфигурирующий Ваш сервер по сети. Разумно для пользователя выполнить и сервер и административное средство на той же машине.
И традиционный Mac OS и Mac OS X поддерживают этот вид обратной петли TCP/IP, включая стандартные 127.0.0.1 петлевых адреса. Однако существует несколько протестов, в зависимости от Вашей версии системы.
Обратная петля на Mac OS X
Mac OS X штабель TCP/IP всегда загружается, и таким образом петлевой адрес, всегда доступен. Передача через петлевой адрес никогда не инициирует злонамеренный вызов на Mac OS X.
Единственный протест с обратной петлей на Mac OS X включает Классику. 127.0.0.1 петлевых адреса работают между всеми программами, работающими в неклассических средах (Углерод, Какао, BSD, Java) и между всеми программами, работающими в Классике, но не работают между неклассическими и Классическими программами. Таким образом, если у Вас есть сервер, работающий в Классике, Вы не можете соединиться с нею с помощью 127.0.0.1 из неклассического приложения, и наоборот.
Обходное решение не должно использовать 127.0.0.1 и фактически соединиться с совместно используемым IP-адресом. Конечно, попытка получить этот совместно используемый IP-адрес может вызвать другие проблемы, как описано в начале этого technote.
Обратная петля на традиционном Mac OS X
Обратная петля на традиционном Mac OS не является почти столь же прямой, как это находится на Mac OS X. Когда машина сконфигурирована для коммутируемого соединения, проблемы происходят. Помните, что на традиционном Mac OS, открытии провайдера TCP/IP, заставляет штабель TCP/IP загружаться, и загружающий штабель TCP/IP может заставить модем набирать. Даже если Вы просто используете конечную точку, чтобы говорить с собой, это - истина. Нет действительно хорошего обходного решения к этой проблеме.
Одно обходное решение далекое от идеального должно реконфигурировать TCP/IP для не соединения через модем. Если никакая другая подходящая ссылка не доступна, можно всегда конфигурировать TCP/IP «МАКИПУ» (с обращением руководства) и конфигурировать AppleTalk к «Удаленному Только». Рисунок 3 показывает то, на что это могло бы быть похожим.

Возможно пользоваться библиотекой Network Setup, чтобы программно создать и переключиться на эти настройки.
Сводка
TCP/IP больше не ограничивается настольными машинами на Ethernet. Ваш код не должен делать ложные предположения о среде TCP/IP и должен адаптироваться к радикальным изменениям в среде TCP/IP, поскольку пользователь реконфигурировал и перемещает их компьютер. Ваш код должен также стремиться избежать раздражающих пользователей с коммутируемыми соединениями путем набора номера их модема неожиданно. Информация в этом technote поможет Вам записать программное обеспечение, которое является удовольствием использовать в динамической среде TCP/IP.
Ссылки
Apple, «в Macintosh: объединяясь в сеть с открытым транспортом», Apple, 1997
Apple, «в Macintosh: настройка сети», Apple, 2000
Apple, «в Mac OS X: обзор платформы конфигурации системы», Apple, 2002
J Postel, J Рейнольдс, «Интернет RFC 959: протокол передачи файлов (FTP)», сетевая рабочая группа IETF, 1985
W Ричард Стивенс, «сетевое программирование UNIX: сети APIs: сокеты и XTI», Прентис Холл, 1998, ISBN 013490012X
DTS Technote 1083 «Слабое соединение к фрагменту кода основанная на менеджере совместно используемая библиотека»
DTS Mac OS «Technote 1121 года 8.1»
DTS Mac OS «Technote 1176 года 9»
Пример кода DTS «OTSimpleServerHTTP»
Пример кода DTS «MoreSCF»
Пример кода DTS «MoreNetworkSetup»
Ранняя история редакций
Дата | Примечания |
|---|---|
01.11.1998 | Первоначально записанный. |
02.01.2000 | Обновленный для решения некоторых проблем в примере кода, ссылочном MoreNetworkSetup вместо OTTCPWillDial, документируют граничный случай в алгоритме предотвращения злонамеренного вызова, используемом MoreNetworkSetup, и ссылаются на уведомления загрузки и разгрузки штабеля, представленные в, Открывают Transport 2.5. |
17.11.2000 | Обновленный для расширения обсуждения IP-адреса, включая определенные подсказки о том, как связать конечные точки. |
22.08.2002 | Значительное обновление для охватывания проблем Mac OS X, включая сокеты BSD, Открыть библиотеку совместимости Transport и платформу Конфигурации системы. |
История версии документа
| Дата | Примечания |
|---|---|
| 27.07.2011 | Переформатированное содержание и внесло незначительные редакционные изменения. |
| 27.08.2002 | Новый документ, описывающий часть запутанности контакта с TCP/IP в динамической среде, такой как Mac OS X. |