网络之Socket详解

网络之Socket详解

1.什么是Socket?

Socket本质上还是文件,因为Linux上一切皆文件。Socket也有对应的文件描述符(fd)。文件描述符相关的参考另外一篇博客。

http://blog.csdn.net/weililansehudiefei/article/details/78113082

在这里简单就认为,它是对应着一个文件的,就可以。

Socket位于TCP/IP之上,通过Socket可以方便的进行通信连接。对外屏蔽了复杂的TCP/IP。

2.Socket连接详解

Socket连接建立的基本过程如下:

接下来就按照这个流程进行

1.int socket(int domain,int type,int protocol);

该方法 返回一个socket_fd,即socket的文件描述符

domain:说明我们网络程式所在的主机采用的通讯协族(AF_UNIX和AF_INET等). AF_UNIX只能够用于单一的Unix系统进程间通信,而AF_INET是针对Internet的,因而能允许在远程主机之间通信(当我们 man socket时发现 domain可选项是 PF_*而不是AF_*,因为glibc是posix的实现所以用PF代替了AF,不过我们都能使用的).

type:我们网络程式所采用的通讯协议(SOCK_STREAM,SOCK_DGRAM等)SOCK_STREAM表明我们用的是TCP协议,这样会提供按顺序的,可靠,双向,面向连接的比特流. SOCK_DGRAM 表明我们用的是UDP协议,这样只会提供定长的,不可靠,无连接的通信.

protocol:由于我们指定了type,所以这个地方我们一般只要用0来代替就能了 socket为网络通讯做基本的准备.成功时返回文件描述符,失败时返回-1,看errno可知道出错的周详情况.

2.int bind(SOCKET socketfd, const struct sockaddr* address, socklen_t address_len);

sockfd:是由上一步socket调用返回的文件描述符.

addrlen:是sockaddr结构的长度.

my_addr:是个指向sockaddr的指针.在<linux/socket.h>中有 sockaddr的定义

       struct sockaddr{

               unisgned short  as_family;

               char           sa_data[14];

               };

不过由于系统的兼容性,我们一般不用这个头文件,而使用另外一个结构(struct   sockaddr_in)来代替.在<linux/in.h>中有sockaddr_in的定义 

        struct sockaddr_in{

               unsigned short         sin_family;     

               unsigned short int      sin_port;

               struct in_addr          sin_addr;

               unsigned char          sin_zero[8];

我们主要使用Internet所以sin_family一般为AF_INET,sin_addr设置为INADDR_ANY表示能和所有的主机通信,sin_port是我们要监听的端口号.sin_zero[8]是用来填充的. bind将本地的端口同socket返回的文件描述符捆绑在一起.成功是返回0,失败的情况和socket相同

3.int listen(int socketfd,int backlog); 

ilsten通过socket套接字和该套接字绑定的IP信息在内核开启监听,并且返回监听描述符。此处监听工作交给内核处理,代码本身不阻塞,但内核对应端口一直在做监听工作。同时维护两个队列,一个是请求队列,一个是就绪队列,大小由backlog决定。

4.int accept(int sockfd,struct sockaddr *addr, socklen_t *addrlen);

接受连接请求,代码默认阻塞。accept实际上是在从内核listen维护的就绪队列中取描述符。accept成功时返回最后的服务器端的文件描述符。重要:这里返回的是一个新的Socket,即socketfd_new.而不是最开始创建的socketfd。用socket_new进行与客户端的通信。

服务器的一个端口,是只能有一个socket绑定的。新生成的socketfd_new虽然有和处理连接请求的socket一样的ip和端口,但是他门不占用端口。我的理解,就是这些新生成的socketfd_new,没有进行bind的操作,所以没有和内核绑定,所以没出现冲突。而socketfd本质上有五大因素决定(fd,src_ip,src_port,des_ip,des_port)。socket里是存放了双方的ip的。

所以,accept方法返回的socketfd_new,已经有了双端的ip和端口,那么久可以进行通信了。

那么,当客户端发送数据过来的时候,究竟是与哪一个socket对象通信呢?   

客户端发送过来的数据可以分为2种,一种是连接请求,一种是已经建立好连接后的数据传输。   

由于TCP/IP协议栈是维护着一个接收和发送缓冲区的。在接收到来自客户端的数据包后,服务器端的TCP/IP协议栈应该会做如下处理:如果收到的是请求连接的数据包,则传给监听着连接请求端口的socetfd套接字,进行accept处理;如果是已经建立过连接后的客户端数据包,则将数据放入接收缓冲区。这样,当服务器端需要读取指定客户端的数据时,则可以利用socketfd_new 套接字通过recv或者read函数到缓冲区里面去取指定的数据(因为socketfd_new代表的socket对象记录了客户端IP和端口,因此可以鉴别)。

5.int connect(int sockfd,const struct sockaddr *addr, socklen_t addrlen)

sockfd:socket:客户端socket返回的文件描述符.

serv_addr:储存了服务器端的连接信息.其中sin_add是服务端的地址

addrlen:serv_addr的长度

connect函数是客户端用来同服务端连接的.成功时返回0,sockfd是同服务端通讯的文件描述符失败时返回-1

原文:https://blog.csdn.net/weililansehudiefei/article/details/78111569

猜你喜欢

转载自www.cnblogs.com/aaronRhythm/p/11007999.html