我们可以将Socket(套接字)解释为插座,这样的话更便于我们理解,具体为:
1 可以将每一个插头理解为一个SocketID,两孔插头为TCP,三孔为UDP,所有的插头都由管家(内核)保管,每次只能向他申请一个插头。一个主机或服务器只有一个插排(IP地址),上面有很多插孔(port)。
serv_sock= socket(PF_INFT,SOCK_STREAM,0);
这个函数可以理解为向管家申请一个插头,由于第二个参数为TCP,所以管家给了你一个两孔插头,这个两孔插头上有一个特定的标号,为serv_sock.
2 但是,插排上的插孔辣莫多,我们应该插哪一个呢?其实我们在往上插的时候会根据一张表往上插,这张表会告诉你应该拿起哪个插头(协议族),然后是正着还是反着(大端还是小端),往这个插排(服务器IP地址)上的某一个特定的插孔上插(端口)。这张表我们会提前规划好:
string port;
std::cin>>port;
struct sockaddr_in serv_adr,clnt_adr;
memset(&serv_adr,0,sizeof(serv_adr));
aerv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(port));
bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr));
bind函数便根据我们提供的表(serv_adr)把申请的两孔插头(serv_sock)和插孔(port)绑定到了一起.
3,假设所有的插线都为数据线,即可进行数据传输。当有数据发来时必须对数据进行处理,所以调用
listen(serv_sock,5);
这个函数便是监听数据线(serv_sock)是否有数据传输。第二个参数为 最大排队的连接个数。
4,但是,这个插排是个服务器插排,端口信息大家都知道,很多插头都想往这个插孔(端口)上插并传输数据,强行解释吧- -!比如插头2想往这个1号插孔上插,所以他先给事先在1号插孔上的插头0(serv_sock,其监听用的socket)说:“我们也想插一插,请大哥通融一下”。这时listen函数便起作用了,他此时知道了插头2想插到1号插孔上。但是插孔只有一个,已经被插头0占了,怎么办?
5,下面accept函数便起作用了。
accept(serv_sock,(struct sockaddr*)&clnt_adr,&adr_sz);
accept函数根据插头0(serv_sock,监听socket)传来的信息,知道了插头2也想插1号插孔,便拿出一张表,把这个插头2的信息记录下来(IP地址,port,保存到clnt_adr里,把大小记录到adr_sz里),因为1号插孔已经被插头0占了,所以他拿出事先准备的1号插孔的复制版,这是一个单独的插孔,和1号插孔功能一模一样,让插头2 插了上去,并给他重新起了一个标志号(clnt_sock)并返回,将那张表还贴在了他们身上。