把最近两天研究Linux下socket编程的成果总结一下。
向网络方向发展,socket编程是首先要解决的问题。之前虽然调过socket的程序,但是理解不深,或者说根本没去理解,敲个代码,调通OK。
既然发起了《计算机网络》的读书计划,也意识到只看书不做代码不可能有深入的理解,就把第三章好好的研究一下,实现几个小例子吧。即使做的不好,也是非常有意义的。什么东西都要经历从不好到好的一个过程。
实现的第一个例子:把socket通信调通,达到能自己不看参考写出来的程度。
准备实现的第二个例子:自定义一个小的协议,用socket传输协议。
准备实现的第三个例子:做一个C/S模型,客户端可以登录,服务端能响应客户端的请求。
要求:体现出网络通信的分层结构。
可以响应5用户同时登录。
言归正传,先说一下几个结构体吧。老是记混,有时候还不记得头文件,这次把它们找出来了,以后就省事了。
第一个结构
Struct sockaddr
{
Unsigned short int sa_family;
Unsigned char sa_data[14];
}
在/usr/include/sys/socket.h里
与sockaddr同等的结构
Sturct sockaddr_in
{
Unsigned short int sin_family;
Unsigned short int sin_port;
Struct in_addr sin_addr;
Unsigned char sin_zero[8];
}
在/usr/include/netinet/in.h里
第三个结构:
Typedef uint32_t in_addr_t;
Struct in_addr
{
In_addr_t s_addr;
};
在/usr/include/netinet/in.h里
我的理解:
到底什么是socket呢?socket就是一种标志,通过IP和端口唯一的标志一个网络中的一个主机上的一个进程,其中IP确定主机,端口确定进程。
什么是socket通信呢?简单的可以这样理解:实现网络中两个不同主机中的进程通信。
说到底就是两个进程在通信,通信就是交换信息。
如何实现?Linux下的一切都是文件,socket也是一种文件,只是比较特别,调用socket()返回的就是一个int型的文件标识,调用bind()后,使这个文件与主机中的一个进程对应起来。然后一个去Listen(),等待别人的连接,一个主动去连接,所谓连接就是使上面讲的两个文件发生关联。连接建立以后,就像对文件一样的操作,一个写,另一个读。
在看socket的时候,开始对Listen和accept很不理解,就找了socket的源码来看看,当然是对着源码分析看的,呵呵。发现原来是这个样子:
在调用accept的时候,内核重新生成了一个socket。而且每调用一次生成一个socket。新生成的socket用来通信,即send & recv。而Listen的那个socket还在监听。把连接的socket放到一个hash表里,而调用一次accept就从队列里取走一个socket处理。打个形象的比喻:“只取蛋,不杀鸡”。