前几章参考:
1-引言
2-Objective-C 编程
3-类、对象和方法
4-数据类型和表达式
5-循环结构
6-选择结构
7-类
8-继承
9-多态、动态类型和动态绑定
10-变量和数据类型
11-分类和协议
预处理和c语言差不多。
预处理程序是Objective-C编译过程的一部分,它可以识别散布在程序中的特定语句。预处理程序使用井号#标记,这个符号必须是一行中的第一个非空格字符。
#define:
#define语句的基本用途之一就是给符号名称指定程序常量。
预定义名称不是变量。因此,不能为它赋值,除非替换指定值的结果实际是一个变量。
#define语句经常放在程序的开始,但#import或include语句之后。
预定义的名称和变量的行为方式不同:没有局部定义之类的说法。
所有预定义的名称都用大写,这样容易区分一个名称是变量名、对象名、类名,还是预定义名称。
事实上,预定义名称一出现,预处理程序就执行文本替换,这可以解释为什么通常不能使用分号结束#define语句的原因。
注意,重新定义底层语言语法的(#define AND &&)行为通常不是好的编程习惯,而且不容易让他人理解你的代码。
如果需要第二行,那么上一行的最后一个字符必须是反斜杠。\
注意,在定义有参数的名称时,预定义名称和参数列表的左括号之前不允许空格。后面使用参数的地方要用括号括起来。
#define SQUARE(x) ((x) * (*))
#import:
这个主要能区别“”,和<>。“”是在本源码查询,<>是在系统路径查询。
#ifdef, #endif, #else, #ifndef和#undef这些都和c语言一样。
#ifdef DEBUG
#if defined (DEBUG)
这里就不多说了。
一、构造
构造函数不能为虚函数
派生类要先调用基类的构造函数,而不能直接覆盖基类的构造函数。
所以在派生类不能再成员初始化列表中初始化基类的成员
见如下例子:
class Base { public: Base(double dNum) : nBase(1) , dBase(dNum) { } int ShowNum(){return nBase;} protected: int nBase; double dBase; private: }; class Derived : public Base { public: Derived(double dNum) : Base(dNum) , nBase(3) { nBase = 2; } protected: private: };
会在,nBase(3)处报错 error C2614: “Derived”: 非法的成员初始化:“nBase”不是基或成员
二、待续......
套接字有三种类型:流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM)及原始套接字。
socket()
|
bind()
|
listen()
| socket()
accept() |
| connect()
| |
read() write()
| |
write() read()
| |
close() close()
socket()
|
bind()
| socket()
listen() |
| bind()
readfrom() |
| <--------- sendto()
| |
sendto() -----> readfrom()
| |
close() close()
struct sockaddr {
unsigned short sa_family; /* address族, AF_xxx */
char sa_data[14]; /* 14 bytes的协议地址 */
};
sa_family 一般来说,都是“AFINET”。
sa_data 包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一切的。为了处理struct sockaddr, 程序员建立了另外一个相似的结构 struct sockaddr_in:
struct sockaddr_in (“in” 代表 “Internet”)
struct sockaddr_in {
short int sin_family; /* Internet地址族 */
unsigned short int sin_port; /* 端口号 */
struct in_addr sin_addr; /* Internet地址 */
unsigned char sin_zero[8]; /* 添0(和struct sockaddr一样大小)*/
};
这个结构提供了方便的手段来访问socket address(struct sockaddr)结构中的每一个元素。注意sin_zero[8] 是为了是两个结构在内存中具有相同的尺寸,使用sockaddr_in 的时候要把sin_zero 全部设成零值(使用bzero()或memset()函数)。而且,有一点很重要,就是一个指向struct sockaddr_in 的指针可以声明指向一个sturct sockaddr 的结构。所以虽然socket() 函数需要一个structaddr * ,你也可以给他一个sockaddr_in
* 。注意在structsockaddr_in 中,sin_family 相当于在 struct sockaddr 中的sa_family,需要设成“AF_INET”。
最后一定要保证sin_port 和sin_addr 必须是网络字节顺序。
/* 因特网地址 (a structure for historical reasons) */
struct in_addr {
unsigned long s_addr;
};
如果你声明了一个“ ina ” 作为一个struct sockaddr_in 的结构, 那么“ina.sin_addr.s_addr”就是4 个字节的IP 地址(按网络字节顺序排放)。需要注意的是,即使你的系统仍然使用联合而不是结构来表示struct in_addr,你仍然可以用上面的方法得到4 个字节的IP 地址。
在struct sockaddr_in 中的sin_addr和sin_port他们的字节顺序都是网络字节顺序,而sin_family却不是网络字节顺序的。
ina.sin_addr.s_addr = inet_addr(“166.111.69.52”);
inet_addr() 返回的地址已经是网络字节顺序了,你没有必要再去调用htonl() 函数。
printf(“%s”, inet_ntoa(ina.sin_addr));
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain , int type , int protocol);
AF_INET
SOCK_STREAM、SOCK_DGRAM
0
错误返回-1,全局变量errno被设置为错误码。
#include <sys/types.h>
#include <sys/socket.h>
int bind (int sockfd , struct sockaddr *my_addr , int addrlen) ;
sockfd 是由socket()函数返回的套接字描述符。
my_addr 是一个指向struct sockaddr 的指针,包含有关你的地址的信息:名称、端口和IP 地址。
addrlen 可以设置为sizeof(struct sockaddr)。
#include <sys/types.h>
#include <sys/socket.h>
int connect (int sockfd, struct sockaddr *serv_addr, int addrlen);
sockfd :套接字文件描述符,由socket()函数返回的。
serv_addr 是一个存储远程计算机的IP 地址和端口信息的结构。
addrlen 应该是sizeof(struct sockaddr)。
#include <sys/socket.h>
int listen(int sockfd, int backlog);
sockfd 是一个套接字描述符,由socket()系统调用获得。
backlog 是未经过处理的连接请求队列可以容纳的最大数目。
#include <sys/socket.h>
int accept(int sockfd, void *addr, int *addrlen);
sockfd 是正在listen() 的一个套接字描述符。
addr 一般是一个指向struct sockaddr_in 结构的指针;里面存储着远程连接过来的计算机的信息(比如远程计算机的IP 地址和端口)。
addrlen 是一个本地的整型数值,在它的地址传给accept() 前它的值应该是sizeof(struct sockaddr_in);accept()不会在addr 中存储多余addrlen bytes 大小的数据。如果accept()函数在addr 中存储的数据量不足addrlen,则accept()函数会改变addrlen 的值来反应这个情况。
#include <sys/types.h>
#include <sys/socket.h>
int send(int sockfd, const void *msg, int len, int flags);
sockfd 是代表你与远程程序连接的套接字描述符。
msg 是一个指针,指向你想发送的信息的地址。
len 是你想发送信息的长度。
flags 发送标记。一般都设为0(你可以查看send 的man pages来获得其他的参数值并且明白各个参数所代表的含义)。
#include <sys/types.h>
#include <sys/socket.h>
int recv(int sockfd, void *buf, int len, unsigned int flags);
sockfd 是你要读取数据的套接字描述符。
buf 是一个指针,指向你能存储数据的内存缓存区域。
len 是缓存区的最大尺寸。
flags 是recv() 函数的一个标志,一般都为0 (具体的其他数值和含义请参考recv()的man pages)。
#include <sys/types.h>
#include <sys/socket.h>
int sendto(int sockfd, const void *msg, int len, unsigned int flags,const struct sockaddr *to, int tolen);
sockfd 是代表你与远程程序连接的套接字描述符。
msg 是一个指针,指向你想发送的信息的地址。
len 是你想发送信息的长度。
flags 发送标记。一般都设为0。(你可以查看send 的man pages 来获得其他的参数值并且明白各个参数所代表的含义)
to 是一个指向struct sockaddr 结构的指针,里面包含了远程主机的IP 地址和端口数据。
tolen 只是指出了struct sockaddr 在内存中的大小sizeof(struct sockaddr)。
#include <sys/types.h>
#include <sys/socket.h>
int recvfrom(int sockfd, void *buf, int len, unsigned int flags,struct sockaddr *from, int *fromlen);
sockfd 是你要读取数据的套接字描述符。
buf 是一个指针,指向你能存储数据的内存缓存区域。
len 是缓存区的最大尺寸。
flags 是recv() 函数的一个标志,一般都为0 (具体的其他数值和含义请参考recv()的man pages)。
from 是一个本地指针,指向一个struct sockaddr 的结构(里面存有源IP 地址和端口数).
fromlen 是一个指向一个int 型数据的指针,它的大小应该是sizeof ( struct sockaddr).当函数返回的时候,formlen 指向的数据是form 指向的struct sockaddr 的实际大小.
#include <sys/socket.h>
int shutdown(int sockfd, int how);
sockfd 是一个你所想关闭的套接字描述符.
how 可以取下面的值。0 表示不允许以后数据的接收操;1 表示不允许以后数据的发送操作;2 表示和close()