TCP控制你的数据按顺序到达,并且没有错。因为TCP使用的是流式套接字。
UDP数据包协议,他传输一个数据报,可能会到达,可能到达了但是数据颠倒了,所以传输的是不可靠的数据。
udp包将会使用一种叫做ACK命令包来保证数据不会丢失。
找个源程序试试。
什么是 socket?
它是使用 标准Unix 文件描述符 (file descriptor) 和其它程序通讯的方式。
网络分层模型,把它对应 到 Unix,结果是:单独列举不容易记忆,这里用unix做对应
应用层(Application Layer) (telnet, ftp,等等)
传输层(Host-to-Host Transport Layer) (TCP,UDP)
Internet层(Internet Layer) (IP和路由)
网络访问层 (NetworkAccessLayer)(网络层,数据链路层和物理层)
数据结构 struct sockaddr_in

为了处理struct sockaddr,程序员创造了一个并列的结构: struct sockaddr_in ("in" 代表 "Internet"。)
struct sockaddr_in {
short int sin_family; /* 通信类型 */
unsigned short int sin_port; /* 端口 */
struct in_addr sin_addr; /* Internet 地址 */
unsigned char sin_zero[8]; /* 与sockaddr结构的长度相同*/
};
如果你声明 "ina" 是数据结构 struct sockaddr_in 的实例,那么 "ina.sin_addr.s_addr" 就储 存4字节的 IP 地址(使用网络字节顺序)。
网络到本机字节顺序的转 换
htons()--"Host to Network Short"
htonl()--"Host to Network Long"
ntohs()--"Network to Host Short"
ntohl()--"Network to Host Long"
为什么在数据结构 struct sockaddr_in 中, sin_addr 和 sin_port 需要转换为网络字节顺序,而sin_family 需不需要呢? 答案是: sin_addr 和 sin_port 分别封装在包的 IP 和 UDP 层。因此,它们必须要 是网络字节顺序。但是 sin_family 域只是被内核 (kernel) 使用来决定在数 据结构中包含什么类型的地址,所以它必须是本机字节顺序。同时, sin_family 没有发送到网络上,它们可以是本机字节顺序。
首先,假设你已经有了一个sockaddr_in结构体ina,你有一个IP地 址"132.241.5.10"要储存在其中,你就要用到函数inet_addr(),将IP地址从 点数格式转换成无符号长整型。使用方法如下:
ina.sin_addr.s_addr = inet_addr("132.241.5.10");
注意,inet_addr()返回的地址已经是网络字节格式,所以你无需再调用 函数htonl()。 网络字节的转换,主要会影响到可移植性。
send() 返回实际发送的数据的字节数--它可能小于你要求发送的数 目!它在错误的时候返回-1,并设置 errno
recv() 函数很相似:
int recv(int sockfd, void *buf, int len, unsigned int flags);
sockfd 是要读的套接字描述符。buf 是要读的信息的缓冲。len 是缓 冲的最大长度。flags 可以设置为0。(请参考recv() 的 man page。) recv() 返回实际读入缓冲的数据的字节数。或者在错误的时候返回-1, 同时设置 errno。
记住,如果你用 connect() 连接一个数据报套接字,你可以简单的调 用 send() 和 recv() 来满足你的要求。这个时候依然是数据报套接字,依 然使用 UDP,系统套接字接口会为你自动加上了目标和源的信息。
域名服务(DNS)
如果你不知道 DNS 的意思,那么我告诉你,它代表域名服务(Domain Name Service)。它主要的功能是:你给它一个容易记忆的某站点的地址,
-------------------------------------------------------------------------------------------------------------------------------
储备知识:
WSAStartup
函数定义int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );
第一个参数wVersionRequested明程序请求使用的Socket版本,其中高位字节指明副版本、低位字节指明主版本;操作系统利用第二个参数返回请求的Socket的版本信息。lpWSAData 指向WSADATA数据结构的指针,用来接收Windows Sockets[1]实现的细节。
当一个应用程序调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的Socket库,然后绑定找到的Socket库到该应用程序中。以后应用程序就可以调用所请求的Socket库中的其它Socket函数了。
MAKEWORD 宏 这个宏创建一个无符号16位整形,通过连接两个给定的无符号参数WORD MAKEWORD(
BYTE bLow, //指定新变量的低字节序;
BYTE bHigh //指定新变量的高字节序;
);
AF_INET AF 表示ADDRESS FAMILY 地址族
- - (void)loadDataFromServerWithURL:(NSURL *)url
- {
- NSString * host = [url host];
- NSNumber * port = [url port];
- // Create socket
- //
- int socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0);
- if (-1 == socketFileDescriptor) {
- NSLog(@"Failed to create socket.");
- return;
- }
- // Get IP address from host
- //
- struct hostent * remoteHostEnt = gethostbyname([host UTF8String]);
- if (NULL == remoteHostEnt) {
- close(socketFileDescriptor);
- [self networkFailedWithErrorMessage:@"Unable to resolve the hostname of the warehouse server."];
- return;
- }
- struct in_addr * remoteInAddr = (struct in_addr *)remoteHostEnt->h_addr_list[0];
- // Set the socket parameters
- struct sockaddr_in socketParameters;
- socketParameters.sin_family = AF_INET;
- socketParameters.sin_addr = *remoteInAddr;
- socketParameters.sin_port = htons([port intValue]);
- // Connect the socket
- //
- int ret = connect(socketFileDescriptor, (struct sockaddr *) &socketParameters, sizeof(socketParameters));
- if (-1 == ret) {
- close(socketFileDescriptor);
- NSString * errorInfo = [NSString stringWithFormat:@" >> Failed to connect to %@:%@", host, port];
- [self networkFailedWithErrorMessage:errorInfo];
- return;
- }
- NSLog(@" >> Successfully connected to %@:%@", host, port);
- NSMutableData * data = [[NSMutableData alloc] init];
- BOOL waitingForData = YES;
- // Continually receive data until we reach the end of the data
- //
- int maxCount = 5; // just for test.
- int i = 0;
- while (waitingForData && i < maxCount) {
- const char * buffer[1024];
- int length = sizeof(buffer);
- // Read a buffer's amount of data from the socket; the number of bytes read is returned
- //
- int result = recv(socketFileDescriptor, &buffer, length, 0);
- if (result > 0) {
- [data appendBytes:buffer length:result];
- }
- else {
- // if we didn't get any data, stop the receive loop
- //
- waitingForData = NO;
- }
- ++i;
- }
- // Close the socket
- //
- close(socketFileDescriptor);
- [self networkSucceedWithData:data];
- }
- 链接