July 25, 2015 8:26 PM
网络编程->套接字->套接字地址结构。
套接字地址结构可以在两个方向上传递:从进程到内核、从内核到进程!
以Windows作为实例,看看套接字的结构:
/*
* Socket address, internet style.
*/
struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
注意:
套接字地址结构仅在给定主机上使用,虽然结构中的某些字段(例如IP地址和端口号)用在不用主机之间的通信中,但是结构本身并不在主机之间传递!
**
当作为一个参数传递进任何套接字函数时,套接字地址结构总是以引用形式(也就是以指向该结构的指针)来传递,然而以这样的指针作为参数之一的任何套接字函数必须处理来自所支持的任何协议族的套接字地址结构
在如何声明所传递指针的数据类型上存在一个问题?
解决的方法:定义一个通用的套接字数据结构!
Ret = bind(ServerSocket, (struct sockaddr*)&LocalAddr, sizeof(LocalAddr));
**
图一 套接字结构图!
从进程空间到内核空间 | 从内核空间到进程空间 |
---|---|
函数 | bind 、connect 、sendto |
图示 |
使用inet_addr函数(返回值为32位的网络字节序二进制值)易于出现的问题:
1.所有的2^3个可能的二进制都是有效的IP地址(0.0.0.0到255.255.255.255),但是当出错时该函数返回INADDR_NONE常值(通常是一个32位均为1的值),这意味着点分十进制数(255.255.255.255)不能由该函数处理。因为其的二进制值被用于指示函数失败。
改用inet_aton函数!
对结果进行静态存储导致该函数不可重入且非线程安全!!!!!!!!
ssize_t Readn(int fd, void *vptr, size_t n)
{
size_t nleft;
ssize_t nread;
char *ptr;
ptr = vptr;
nleft = n;
while( nleft > 0 )
{
if( ( nread = read(fd,ptr,nleft ) ) < 0 )
{
if( errno == EINTR )
nread = 0;
else
return -1;
}
else if( nread == 0 )
break;
nleft -= nread;
ptr += nread;
}
return ( n - nleft );
}
套接字地址结构是每一个网络程序的重要组成部分,分配它们,填写它们,把指向它们的指针传递给各个套接字函数。
TCP套接字为应用进程提供一个字节流,它们没有记录标记,从TCP套接字read的返回值可能比我们请求的数量少,但是这不表示发生错误。对于文本行交互的应用来说,程序应该按照操作缓冲区而非按照操作文本行来编写。
下图给出TCP客户端和服务段进程之间发生的一些典型事件的时间表!
注意:
1.客户在调用connect前不必非得调用bind函数,因为如果需要的话,内核会确定源IP地址,big选择一个临时端口作为源端口。
2、按照TCP状态转换图(图2-4 原书中!),connect函数导致当前套接字从CLOSED状态(该套接字自从由socket函数创建以来一直所处的状态)转移到SYN_SENT状态,若成功再转移到ESTABLISHED状态,若connect失败则该套接字不再可用,必须关闭,我们不能对这样的套接字再次调用connect函数。
可以通过使用GetEnv函数获取环境变量,来改变程序运行轨迹!!!!!!!!
pid_t pid
int listenfd, connfd
listenfd = socket();
Bind(listenfd,...)
for(;;)
{
connfd = Accept(listenfd,...)
if( ( pid = for() ) == 0 )
{
close(linsenfd);
doit(connfd);
close(connfd);
}
close(connfd);
}