Chansy的N次元空間
没有鹳狸猿,没有河蟹的世界|鹳狸猿とチュウゴクモクズガニのない世界
没有鹳狸猿,没有河蟹的世界|鹳狸猿とチュウゴクモクズガニのない世界
六月 19th, 2011
All languages have something interesting to teach us about the art of programming — and as a Ruby developer almost exclusively, I’ve always been afraid of strongly typed languages like Java and C++, or the great-grand-daddy of them all, C. So when I decided to tackle Cocoa to work on iPhone apps I went in somewhat leery of how I’d have to change, but hopeful that I’d become a better, more versatile programmer. After a few weeks I would say I’ve achieved my goal, but it’s certainly taken a lot of blood, sweat, and tears to get here.
I think a lot of people are in a similar position to me: trying to pick up Objective-C to do iPhone programming, and coming in with only a book or two as their guide. Most of the books out there for learning Cocoa and the iPhone SDK are very good but there are a lot of gotchas and stylistic tricks that really mean the difference between comprehending a statement and staring at it in horror and confusion until Google comes to your rescue. The aim of this blog post is to come to your rescue instead of Google. These are the 8 biggest foul-ups that I wish I had known before I started learning Objective-C. Hopefully you’ll learn something here that will prevent you from making an idiotic mistake I already made.
Seriously, I’m not even kidding. This is THE way to debug hard to find errors in your apps.
As you may or may not know, iPhone apps do not have an automated garbage collector, so you have to release and retain objects manually. Sometimes you accidentally release an object that you intended to hold on to. Your code will not fail until a message is sent to the deallocated instance, at which point your application will crash and you’ll have no idea why. Oh, sure, you’ll have the general EXC_BAD_ACCESS error that tells you you tried to access memory that was deallocated… but that isn’t really helpful.
If you turn on NSZombieEnabled, then deallocated instances are retained in memory but their class is changed to Zombie, so that when they receive a message they raise an error. Now you can actually debug those memory problems.
To turn this on:
Do this right now. You’ll thank me later. Just remember to redact it before you bundle your app to production, because in production, you want instances to be deallocated, not turned into zombies.
This one was difficult for me to wrap my head around.
In most object oriented languages, like Ruby, if you send a method to an object but that object is nil, your program dies messily. This is what amazing gems like Andand are supposed to protect against: nil inadvertently receiving a message and raising an error.
In Objective-C, if nil is sent a message, that’s just fine. In fact I would go so far as to say this is an amazing and distinguishing feature of Objective-C: it is used extensively in the iPhone classes and you should use it too. This allows you to make code sort of like this:
if ([anObjectThatMayBeNil startProcessing]) { // ...code...}You don’t have to test whether or not the object is nil. If this statement isn’t true then either startProcessing failed, or the object wasn’t there: either way, you don’t want to execute the code block. Whether or not this is just madness is certainly open for personal interpretation. Coming from Ruby I sort of like it, but I can see how it can make code very very difficult to debug.
My advice is to embrace the insanity. Objective-C provides a lot of power by allowing you to use objects’ methods even when they may not exist: be careful in how you use this power and your programs will flourish.
This is a really simple and dumb one.
NSString is what most Objective-C classes that want string-like objects expect; they are NOT formed with quotes, but with an at-sign then quotes.
@”This is a valid NSString.”
“This is not, and will raise annoying and mysterious compiler errors if you try to use it.”
Similarly, don’t forget your semi-colons. I know I sound like a noob, but coming from Ruby it’s easy to trip up and just hit enter and then be confused when the compiler dies. Happily in this case at least you get a sensible message so you can find the problem and put in a semi-colon.
Native Objective-C classes (particularly iPhone classes) make extensive use of delegates. They rely on the fact that you can send messages to nil objects without a problem that I discussed earlier: even if you don’t assign a delegate the messages are sent anyway, there’s just no one there to listen to them. It’s like ‘if a function falls in a forest…’ or something like that.
Anyway, delegates are extremely powerful and are one of the cooler elements of style in Objective-C. They allow you to send long-running or complicated tasks off to another object and be certain that you’ll hear back from them eventually, while simultaneously affording you the power of polymorphism in that you can call that task from any object and respond to the task situationally.
An excellent example of this is CoreLocation, the framework the iPhone uses to do location updating. In my iPhone app I have a singleton class Locator that controls access to the CoreLocation framework. It is the delegate of the CLLocationManager like this:
self.locationManager = [[CLLocationManager alloc] init];self.locationManager.delegate = self;[self.locationManager startUpdatingLocation];
When the CLLocationManager receives a location update, it calls a method on the delegate called locationManager:didUpdateToLocation:fromLocation:. All I have to do in my code is implement that method: I know that it will be called if and only if the location was correctly received. There’s another method for locationManager errors.
The power of this, of course, is that one object can have its delegate changed; thus, the delegators can respond to the same call in different ways. Perhaps in one controller in my app I pop up a window after the location has been updated. In another, I animate something. The method is the same for both controllers (locationManager:didUpdateToLocation:fromLocation:): all I’m doing is changing which one is the delegate of CLLocationManager.
Once you get used to this programming style, you’ll really like it.
NSLog(@"Hi there, the object you want is: %@", anObject);
Ruby gives an excellent backtrace when it crashes. Objective-C (even with gdb) leaves a lot to be desired, in my opinion. Log frequently, everywhere, everything, so that when your application mysteriously crashes (and it will) you know around where so hopefully you can find the foul-up.
By the way, the %@ inside the NSString up there? That’s the syntax for object substitution. This ONLY works for NSObjects, and it calls their description method. If you try to do it on a regular C type it’ll crash, so this is totally wrong:
int i = 1;NSLog(@"The number is: %@", i); // BOOM CRASH!
Instead, you should use the correct string substitution:
int i = 1;NSLog(@"The number is: %i", i); // sweet, sweet success
An easy gotcha to miss. Check out the Cocoa string substitution documentation for all the other types out there.
A closely-related corollary to the NSLog advice: give all your custom object classes a description method.
- (NSString *)description {return self.name;}Now when you log them with NSLog they’ll return a sensible string, instead of nil.
Use strong typing when it seems sensible, but you don’t have to be married to it because Objective-C certainly isn’t. Any Objective-C object can be declared with the type ‘id’ rather than its particular class. This allows you to use some potentially dangerous instances of polymorphism:
Duck *aDuck = [[Duck alloc] init];Goose *aGoose = [[Goose alloc] init];Pond *bigLake = [[Pond alloc] init];bigLake.inhabitant = aDuck;[bigLake.inhabitant quack]; // The duck says: "quack!"bigLake.inhabitant = aGoose;[bigLake.inhabitant quack]; // The goose says: "do I look like a duck to you?"
This is made possible by a simple declaration in the Pond class:
@interface Pond : NSObject {id *inhabitant;}@property (nonatomic, retain) id *inhabitant;Now Objective-C doesn’t care what the inhabitant is, only that it descends from NSObject (that defines id). This will sensibly warn you at compile-time that the inhabitant might not respond to quack, though, so be careful with this power. If you send a bad method to an object it isn’t the same as if you sent a message to nil: your program will crash if the object has no such method defined on it.
But still, you can pass all kinds of different objects around now however you like. Just remember to make sure they respond to the method you pass to them before you use them.
I was trying to do something clever with the UIWebView object but it didn’t seem like it was possible with the documentation given to me by the default API viewer. Then Google came to the rescue and showed me the light (or rather, the method webView:shouldStartLoadWithRequest:navigationType:). Even though the documentation is ostensibly complete (and even that won’t be true unless you subscribe to it and download the complete docs), a lot of people have experimented with Cocoa and the iPhone SDK for a lot longer than we have. A quick Google search can sometimes yield surprising results, and you can bet any problem you’ve run into, someone else has already had trouble with.
I’m sure there’s a bunch I missed. My C was very rusty; after using Ruby almost exclusively for a few years, it was difficult to pick up Objective-C. But ultimately I think it was very rewarding. Objective-C is elegant and simple, giving you more than enough rope to hang yourself, or create something really amazing (out of rope, to maintain the metaphor). Just make sure to keep in mind this hit-list of 8 items and your Objective-C programs will flourish. And if you’ve got something to share, post it as a comment, and let the world read your helpful advice!
六月 17th, 2011
by Jeff Tyson
Introduction to How Network Address Translation Works

If you are reading this article, you are most likely connected to the Internet and viewing it at the HowStuffWorks Web site. There's a very good chance that you are using Network Address Translation (NAT) right now.
The Internet has grown larger than anyone ever imagined it could be. Although the exact size is unknown, the current estimate is that there are about 100 million hosts and more than 350 million users actively on the Internet. That is more than the entire population of the United States! In fact, the rate of growth has been such that the Internet is effectively doubling in size each year.
So what does the size of the Internet have to do with NAT? Everything! For a computer to communicate with other computers and Web servers on the Internet, it must have an IP address. An IP address (IP stands for Internet Protocol) is a unique 32-bit number that identifies the location of your computer on a network. Basically, it works like your street address -- as a way to find out exactly where you are and deliver information to you.
When IP addressing first came out, everyone thought that there were plenty of addresses to cover any need. Theoretically, you could have 4,294,967,296 unique addresses (232). The actual number of available addresses is smaller (somewhere between 3.2 and 3.3 billion) because of the way that the addresses are separated into classes, and because some addresses are set aside for multicasting, testing or other special uses.
With the explosion of the Internet and the increase in home networks and business networks, the number of available IP addresses is simply not enough. The obvious solution is to redesign the address format to allow for more possible addresses. This is being developed (called IPv6), but will take several years to implement because it requires modification of the entire infrastructure of the Internet.
This is where NAT (RFC 1631) comes to the rescue. Network Address Translation allows a single device, such as a router, to act as an agent between the Internet (or "public network") and a local (or "private") network. This means that only a single, unique IP address is required to represent an entire group of computers.
But the shortage of IP addresses is only one reason to use NAT. In this edition of HowStuffWorks, you will learn more about how NAT can benefit you. But first, let's take a closer look at NAT and exactly what it can do...
What Does NAT Do?
NAT is like the receptionist in a large office. Let's say you have left instructions with the receptionist not to forward any calls to you unless you request it. Later on, you call a potential client and leave a message for that client to call you back. You tell the receptionist that you are expecting a call from this client and to put her through.
The client calls the main number to your office, which is the only number the client knows. When the client tells the receptionist that she is looking for you, the receptionist checks a lookup table that matches your name with your extension. The receptionist knows that you requested this call, and therefore forwards the caller to your extension.
Developed by Cisco, Network Address Translation is used by a device (firewall, router or computer) that sits between an internal network and the rest of the world. NAT has many forms and can work in several ways:
![]() In static NAT, the computer with the IP address of 192.168.32.10 will always translate to 213.18.123.110. |
![]() In dynamic NAT, the computer with the IP address 192.168.32.10 will translate to the first available address in the range from 213.18.123.100 to 213.18.123.150. |
![]() In overloading, each computer on the private network is translated to the same IP address (213.18.123.100), but with a different port number assignment. |
![]() The internal IP range (237.16.32.xx) is also a registered range used by another network. Therefore, the router is translating the addresses to avoid a potential conflict with another network. It will also translate the registered global IP addresses back to the unregistered local IP addresses when information is sent to the internal network. |
The internal network is usually a LAN (Local Area Network), commonly referred to as the stub domain. A stub domain is a LAN that uses IP addresses internally. Most of the network traffic in a stub domain is local, so it doesn't travel outside the internal network. A stub domain can include both registered and unregistered IP addresses. Of course, any computers that use unregistered IP addresses must use Network Address Translation to communicate with the rest of the world.
NAT Configuration
NAT can be configured in various ways. In the example below, the NATrouter is configured to translate unregistered (inside, local) IPaddresses, that reside on the private (inside) network, to registeredIP addresses. This happens whenever a device on the inside with anunregistered address needs to communicate with the public (outside)network.
![]() IP addresses have different designations based onwhether they are on the private network (stub domain) or on the publicnetwork (Internet), and whether the traffic is incoming or outgoing. |
NAT overloading utilizes a feature of the TCP/IP protocol stack, multiplexing, that allows a computer to maintain several concurrent connections with a remote computer (or computers) using different TCP or UDP ports. An IP packet has a header that contains the following information:
The addresses specify the two machines at each end, while the portnumbers ensure that the connection between the two computers has aunique identifier. The combination of these four numbers defines asingle TCP/IP connection. Each port number uses 16 bits, which meansthat there are a possible 65,536 (216)values. Realistically, since different manufacturers map the ports inslightly different ways, you can expect to have about 4,000 portsavailable.
Dynamic NAT and Overloading
Here's how dynamic NAT works:Here's how overloading works:
Stub Domains
Look at this table to see how the computers on a stub domain might appear to external networks.
Computer | Computer's IP Address | Computer's Port | IP Address | Assigned Port Number |
As you can see, the NAT router stores the IP address and port number of each computer in the address translation table. It then replaces the IP address with its own registered IP address and the port number corresponding to the location, in the table, of the entry for that packet's source computer. So any external network sees the NAT router's IP address and the port number assigned by the router as the source-computer information on each packet.
You can still have some computers on the stub domain that use dedicated IP addresses. You can create an access list of IP addresses that tells the router which computers on the network require NAT. All other IP addresses will pass through untranslated.
The number of simultaneous translations that a router will support are determined mainly by the amount of DRAM (Dynamic Random Access Memory) it has. But since a typical entry in the address-translation table only takes about 160 bytes, a router with 4 MB of DRAM could theoretically process 26,214 simultaneous translations, which is more than enough for most applications.
IANA has set aside specific ranges of IP addresses for use as non-routable, internal network addresses. These addresses are considered unregistered (for more information check out RFC 1918: Address Allocation for Private Internets, which defines these address ranges). No company or agency can claim ownership of unregistered addresses or use them on public computers. Routers are designed to discard (instead of forward) unregistered addresses. What this means is that a packet from a computer with an unregistered address could reach a registered destination computer, but the reply would be discarded by the first router it came to.
There is a range for each of the three classes of IP addresses used for networking:
Although each range is in a different class, your are not required to use any particular range for your internal network. It is a good practice, though, because it greatly diminishes the chance of an IP address conflict.
Security and Administration
Implementing dynamic NAT automatically creates a firewall between your internal network and outside networks, or between your internal network and the Internet. NAT only allows connections that originate inside the stub domain. Essentially, this means that a computer on an external network cannot connect to your computer unless your computer has initiated the contact. You can browse the Internet and connect to a site, and even download a file; but somebody else cannot latch onto your IP address and use it to connect to a port on your computer.
In specific circumstances, Static NAT, also called inbound mapping, allows external devices to initiate connections to computers on the stub domain. For instance, if you wish to go from an inside global address to a specific inside local address that is assigned to your Web server, Static NAT would enable the connection.
![]() Static NAT (inbound mapping) allows a computer on the stub domain to maintain a specific address when communicating with devices outside the network. |
Some NAT routers provide for extensive filtering and traffic logging. Filtering allows your company to control what type of sites employees visit on the Web, preventing them from viewing questionable material. You can use traffic logging to create a log file of what sites are visited and generate various reports from it.
NAT is sometimes confused with proxy servers, but there are definite differences between them. NAT is transparent to the source and to destination computers. Neither one realizes that it is dealing with a third device. But a proxy server is not transparent. The source computer knows that it is making a request to the proxy server and must be configured to do so. The destination computer thinks that the proxy server IS the source computer, and deals with it directly. Also, proxy servers usually work at layer 4 (transport) of the OSI Reference Model or higher, while NAT is a layer 3 (network) protocol. Working at a higher layer makes proxy servers slower than NAT devices in most cases.
![]() NAT operates at the Network layer (layer 3) of the OSI Reference Model -- this is the layer that routers work at. |
A real benefit of NAT is apparent in network administration. For example, you can move your Web server or FTP server to another host computer without having to worry about broken links. Simply change the inbound mapping at the router to reflect the new host. You can also make changes to your internal network easily, because the only external IP address either belongs to the router or comes from a pool of global addresses.
NAT and DHCP (dynamic host configuration protocol ) are a natural fit. You can choose a range of unregistered IP addresses for your stub domain and have the DHCP server dole them out as necessary. It also makes it much easier to scale up your network as your needs grow. You don't have to request more IP addresses from IANA. Instead, you can just increase the range of available IP addresses configured in DHCP to immediately have room for additional computers on your network.
Multi-homing
As businesses rely more and more on the Internet, having multiple points of connection to the Internet is fast becoming an integral part of their network strategy. Multiple connections, known as multi-homing, reduces the chance of a potentially catastrophic shutdown if one of the connections should fail.
In addition to maintaining a reliable connection, multi-homing allows a company to perform load-balancing by lowering the number of computers connecting to the Internet through any single connection. Distributing the load through multiple connections optimizes the performance and can significantly decrease wait times.
Multi-homed networks are often connected to several different ISPs (Internet Service Providers). Each ISP assigns an IP address (or range of IP addresses) to the company. Routers use BGP (Border Gateway Protocol), a part of the TCP/IP protocol suite, to route between networks using different protocols. In a multi-homed network, the router utilizes IBGP (Internal Border Gateway Protocol) on the stub domain side, and EBGP (External Border Gateway Protocol) to communicate with other routers.
Multi-homing really makes a difference if one of the connections to an ISP fails. As soon as the router assigned to connect to that ISP determines that the connection is down, it will reroute all data through one of the other routers.
NAT can be used to facilitate scalable routing for multi-homed, multi-provider connectivity. For more on multi-homing, see Cisco: Enabling Enterprise Multihoming.
For lots more information on NAT and related topics, check out the links on the next page.
Lots More Information
Related HowStuffWorks Articles
More Great Links
近期评论 | 最新のコメント