(2009.10.1 整理自 《Pocket Guide to TCP/IP Sockets (C Version)》)
ONE. socket基础
为了使用TCP,UPD通信,程序首先要请求OS生成套接字实例。这里使用了socket()函数。
Int socket(int PROTOCOLFAMILY, int TYPE, int PROTOCOL)
常数 PF_INET表示互联网协议家族,我们在这里只用到它。
返回任意正数表示成功,-1表示失败。
关闭 int close(int socket) 成功返回0, 失败返回-1
socket API 为了关联套接字和地址信息定义了构造体-sockaddr:
struct sockaddr
{
unsigned short sa_family; /* address family (e.g. AF_INET) */
char sa_data[14]; /* family-specific address information */
};
第一个参数我们只用表示互联网地址家族的常数 AF_INET。
Struct in_addr
{
unsigned long s_addr; /* Internet address(32 bits) */
};
struct sockaddr_in
{
unsigned short sin_family /* Internet protocol (AF_INET) */
unsigned short sin_port; /* address port (16 bits) */
struct in_addr sin_addr; /* Internet address(32 bits) */
char sin_zero[8]; /* Not used */
};
sockaddr_in 是为了使sockaddr结构体数据部分符合互联网协议而修正的。
所以填充了sockaddr_in字段之后,将它cast在sockaddr。
我们先重点研究下TCP的发送接收,因为TCP套接字通信和文件的I/O很相似。
TCP客户端的4个过程:
利用socket() 生成 TCP套接字;
利用connect()定义与服务器的连接;
利用send() 和recv()进行通信;
利用close()断开连接;
int connect(int socket, struct sockaddr * foreignAddress, unsigned int addressLength)
这里的 socket 是由socket()生成的识别号。
ForeignAddress是socketaddr_in类型的指向服务器IP地址和端口号的指针。
AddressLength 固定为sizeof(struct sockaddr_in)
int send(int socket, const void * msg, unsigned int msgLength, int flags)
int recv(int socket, void * rcvBuffer, unsigned int bufferLength, int flags)
send()的默认行为是发送所有数据后block.
recv()默认行为是至少要等一定比特移动之后在BLOCK。
send()和recv()的flags参数可以改变默认行为,为0时是默认行为。
send()和recv()返回发送或接收的字节数或者返回失败信息-1。
下面的程序展示了客户端与叫做“echo”的服务器通信过程,有很多系统为了调试或测试使用这种服务器,这种服务器这是简单地将接收到的信息重新发回客户端。