tcp three questions

One problem: socket structure subject what is the definition?

我们知道,在使用socket编程之前,需要调用socket函数创建一个socket对象,该函数返回该socket对象的描述符。

Function Prototype: int socket (int domain, int type, int protocol);

**那么,这个socket对象究竟是怎么定义的呢?它记录了哪些信息呢?只记录了本机IP及端口、还是目的IP及端口、或者都记录了?**

关于这个问题,大家可以在内核源码里面找,也可以参考这篇文章《struct socket 结构详解》,我们可以看到 socket  结构体的定义如下:   

struct Socket
{
socket_state State;
unsigned Long the flags;
const struct proto_ops * OPS;
struct fasync_struct * fasync_list;
struct File * File;
struct our sock * SK;
wait_queue_head_t the wait;
Short type;
};
wherein, struct sock comprising a sock_common structure, the structure further comprises a sock_common struct inet_sock structure, and some struct inet_sock structure defined as follows:

inet_sock struct
{
struct our sock SK;
#if defined (CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
struct ipv6_pinfo * pinet6;
#endif
__u32 DADDR; // the IPv4 destination address.
__u32 rcv_saddr; // Local IPv4 addresses received.
__u16 dport; // destination port.
__u16 num; // local port (host byte order).

............
}
Thus, we have clear, socket structure recorded only local IP address and port number, destination IP and also recorded port.

Second problem: connect a function of what has been done the operation?

 在TCP客户端,首先调用一个socket()函数,得到一个socket描述符socketfd,然后通过connect函数对服务器进行连接,连接成功后,就可以利用这个socketfd描述符使用send/recv函数收发数据了。

关于connect函数和send函数的原型如下:

int connect( int sockfd, const struct sockaddr* server_addr, socklen_t addrlen)

int send (int sockfd, const void * msg, int len, int flags);
Well, now the confusion is, why send function only incoming sockfd can know ip and port number of the server?

其实,由“问题一”中的答案我们已经很清楚了,sockfd 描述符所描述的socket对象不仅包含了本地IP和端口,同时也包含了服务器的IP和端口,这样,才能使得send函数只需要传入sockfd 即可知道该把数据发向什么地方。而代码中,

Destination IP port and appeared only in the connect function, therefore, must be connect function after the connection is successfully established, the destination port and IP socket object written descriptor sockfd described.

Question three: socket accept function generated have not taken the new port?

首先,回顾一下accept函数,原型如下:

int accept(int sockfd, struct sockaddr* addr, socklen_t* len)

accept函数主要用于服务器端,一般位于listen函数之后,默认会阻塞进程,直到有一个客户请求连接,建立好连接后,它返回的一个新的套接字 socketfd_new ,此后,服务器端即可使用这个新的套接字socketfd_new与该客户端进行通信,而sockfd 则继续用于监听其他客户端的连接请求。

至此,我的困惑产生了,这个新的套接字 socketfd_new 与监听套接字sockfd 是什么关系?它所代表的socket对象包含了哪些信息?socketfd_new 是否占用了新的端口与客户端通信?

先简单分析一番,由于网站的服务器也是一种TCP服务器,使用的是80端口,并不会因客户端的连接而产生新的端口给客户端服务,该客户端依然是向服务器端的80端口发送数据,其他客户端依然向80端口申请连接。因此,可以判断,socketfd_new 并没有占用新的端口与客户端通信,依然使用的是与监听套接字socketfd_new一样的端口号。

那这么说,难道一个端口可以被两个socket对象绑定?当客户端发送数据过来的时候,究竟是与哪一个socket对象通信呢?

我是这么理解的(欢迎拍砖)。

首先,一个端口肯定只能绑定一个socket。我认为,服务器端的端口在bind的时候已经绑定到了监听套接字socetfd所描述的对象上,accept函数新创建的socket对象其实并没有进行端口的占有,而是复制了socetfd的本地IP和端口号,并且记录了连接过来的客户端的IP和端口号。

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

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

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

Reprinted from https://www.cnblogs.com/langren1992/p/5101380.html

Published 90 original articles · won praise 13 · views 10000 +

Guess you like

Origin blog.csdn.net/weixin_44030580/article/details/104492102