TCP/IP 学习笔记

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  

 
TCP/IP 学习笔记 - 培亮 - 小老虎的博客
 这个结构 为许多类型的套接字储存套接字地址信息;sa_family 能够是各种各样的类型,但是在这篇文章中都是 "AF_INET"。

为了处理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 地址族

  1. - (void)loadDataFromServerWithURL:(NSURL *)url
  2. {
  3.     NSString * host = [url host];
  4.     NSNumber * port = [url port];
  5.     // Create socket
  6.     //
  7.     int socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0);
  8.     if (-1 == socketFileDescriptor) {
  9.         NSLog(@"Failed to create socket.");
  10.         return;
  11.     }
  12.     // Get IP address from host
  13.     //
  14.     struct hostent * remoteHostEnt = gethostbyname([host UTF8String]);
  15.     if (NULL == remoteHostEnt) {
  16.         close(socketFileDescriptor);
  17.         [self networkFailedWithErrorMessage:@"Unable to resolve the hostname of the warehouse server."];
  18.         return;
  19.     }
  20.     struct in_addr * remoteInAddr = (struct in_addr *)remoteHostEnt->h_addr_list[0];
  21.     // Set the socket parameters
  22. struct sockaddr_in socketParameters;
  23. socketParameters.sin_family = AF_INET;
  24. socketParameters.sin_addr = *remoteInAddr;
  25. socketParameters.sin_port = htons([port intValue]);
  26.     // Connect the socket
  27.     //
  28.     int ret = connect(socketFileDescriptor, (struct sockaddr *) &socketParameters, sizeof(socketParameters));
  29. if (-1 == ret) {
  30. close(socketFileDescriptor);
  31.         NSString * errorInfo = [NSString stringWithFormat:@" >> Failed to connect to %@:%@", host, port];
  32.         [self networkFailedWithErrorMessage:errorInfo];
  33. return;
  34. }
  35.     NSLog(@" >> Successfully connected to %@:%@", host, port);
  36.     NSMutableData * data = [[NSMutableData alloc] init];
  37. BOOL waitingForData = YES;
  38. // Continually receive data until we reach the end of the data
  39.     //
  40.     int maxCount = 5;   // just for test.
  41.     int i = 0;
  42. while (waitingForData && i < maxCount) {
  43. const char * buffer[1024];
  44. int length = sizeof(buffer);
  45. // Read a buffer's amount of data from the socket; the number of bytes read is returned
  46.         //
  47. int result = recv(socketFileDescriptor, &buffer, length, 0);
  48. if (result > 0) {
  49. [data appendBytes:buffer length:result];
  50. }
  51.         else {
  52.             // if we didn't get any data, stop the receive loop
  53.             //
  54. waitingForData = NO;
  55. }
  56.         ++i;
  57. }
  58. // Close the socket
  59.     //
  60. close(socketFileDescriptor);
  61.     [self networkSucceedWithData:data];
  62. }
  63. 链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值