基于TCP的socket详解(Linux系统)

内容有点多建议配合实例学习:https://blog.csdn.net/FUN6367/article/details/105294984

1、基于TCP的socket五元组结构

两个程序:Server(服务器程序)、Client(客户端程序)

Server程序的作用:

  (1)程序初始化

   (2)持续监听一个固定的端口

   (3)收到Client的连接后建立一个socket

   (4)与Client进行通信和信息处理:

          ①接受Client通过socket连接发送来的数据,进行相应处理并返回结果

          ②通过socket连接向Client发送信息

   (5)通信结束后中断与Client的连接

Client程序的作用:

   (1)程序初始化

   (2)连接到某个Server上,建立socket连接

   (3)与Server进行通信和信息处理:

          ①接受Server通过socket连接发送来的数据,进行相应处理

          ②通过socket连接向Server发送请求信息

   (5)通信结束后中断Server的连接

2、socket基本概念

  (1)socket是网络编程的一种接口,它是一种特殊的I/O,用socke()函数建立一个socket连接,此函数返回一个整型socket描述符,随后进行数据传输。

  (2)一个IP地址,一个通讯端口,就能确定一个通讯程序的位置。为此开发人员专门设计了一个套接结构,就是把网络程序中所用到的网络地址和端口信息放在一个结构体中。

  (3)一般套接接口地址结构都以“sockaddr”开头。socket根据所使用的协议的不同可以分为TCP套接口和UDP套接口,又称为流式和数据套接口。

UPD与TCP的区别:UDP是一个无连接协议,TCP是个可靠的端对端协议。传输UDP数据包时,LINUX不知道也不关心他们是否已经安全到达目的地,而传输TCP数据包时,则应先建立连接以保证传输的数据被正确接收


socket套接字的数据结构,两个重要的数据类型:sockaddrsockaddr_in,这两个结构类型都是用来保存socket信息的,如IP地址、通信端口等

sockaddr定义:

struct sockaddr
{  
   unsigned short sa_family;       /*一般为AF_INET,代表TCP/IP地址族*/
   char sa_data[14];               /*14个字节,包含IP地址和端口号*/
};

sockaddr_in定义:

struct sockaddr_in
 {   
     short sin_family;           /*AF_INET(地址族)*/
     unsigned short sin_port;    /*端口号(必须要采用网络数据格式)*/
     struct in_addr sin_addr;    /*网络字节序的IP地址,用来存储IP地址*/
     unsigned char sin_zero[8];  /*与SOCKADDR结构保持同样大小*/
 };

in_addr也是一个结构体,可以用来表示一个32位的IPv4地址

#include <arpa/inet.h>
struct in_addr {
    in_addr_t s_addr; 
};
/*
n_addr_t 一般为 32位的unsigned int,其字节顺序为网络顺序(network byte ordered),
即该无符号整数采用大端字节序 。
其中每8位代表一个IP地址位中的一个数值。

例如192.168.3.144记为0x9003a8c0,其中 c0 为192 ,a8 为 168, 03 为 3 , 90 为 144
打印的时候可以调用inet_ntoa()函数将其转换为char *类型。
*/

​#include <netinet/in.h>  
#include <sys/socket.h>   
#include <arpa/inet.h>  

int inet_aton(const char *string, struct in_addr *addr) 
/*
输入参数
    string:包含ASCII表示的IP地址
    addr:是将要用新的IP地址更新的结构
返回值:如果这个函数成功,函数的返回值非零,如果输入地址不正确则会返回零
*/

char*inet_ntoa(struct in_addr in);
/*
输入参数:in :一个网络上的IP地址
返回值:如果正确,返回一个字符指针,指向一块存储着点分格式IP地址的静态缓冲区(同一线程内共享此内存);错误,返回NULL。   
*/

​

 客户端程序用到的一个函数和结构体

#include <netdb.h>

//gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构的指针。
struct hostent *gethostbyname(const char *hostname);
/*
name:指向主机名的指针
返回类型hostent指针
*/

/*该结构记录主机的信息,包括主机名、别名、地址类型、地址长度和地址列表。之所以主机的地址是一个列表的形式,原因是当一个主机有多个网络接口时,自然有多个地址*/
struct hostent
{
	char *h_name;                   //正式主机名
	char **h_aliases;               //主机别名
	int h_addrtype;                 //地址类型; 通常是AF_INET
	int h_length;		            //地址的比特长度
	char **h_addr_list;	            //主机的IP地址列表,网络字节顺序
	#define h_addr h_addr_list[0]   // h_addr_list中的第一地址。
};

 


socket()函数建立一个空的socket

#include <sys/socekt.h>

int socket(int af, int type, int protocol);

/*
  参数描述
    af:一个地址描述。目前仅支持AF_INET格式,也就是说ARPA Internet地址格式。

    type:指定socket类型。新套接口的类型描述类型,如TCP(SOCK_STREAM)TCP(SOCK_STREAM)和 
          UDP(SOCK_DGRAM)。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、 
          SOCK_PACKET、SOCK_SEQPACKET等等。

    protocol:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。常用的协议有, 
              IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,它们分别对应TCP传输协 
              议、UDP传输协议、STCP传输协议、TIPC传输协议。
*/

通常参数的赋值分别为:af(AF_INET)、type(SOCK_STREAM)、protocol(0)

int sockfd = socket(AF_INET, SOCK_STREAM, 0);    //建立一个空的socket

3、socket的一些辅助函数(服务器和客户机的信息函数)

include <arpa/inet.h> 

unsigned short int htons(unsigned short int hostshort);
//主机字节顺序转换成网络字节顺序,对无符号短型进行操作4bytes

unsigned long int htonl(unsigned long int hostlong);
//主机字节顺序转换成网络字节顺序,对无符号长型进行操作8bytes

unsigned short int ntohs(unsigned short int netshort);
//网络字节顺序转换成主机字节顺序,对无符号短型进行操作4bytes

unsigned long int ntohl(unsigned long int netlong);
//网络字节顺序转换成主机字节顺序,对无符号长型进行操作8bytes
#include <sys/types.h>   
#include <sys/socket.h>   
#include <arpa/inet.h>  

int inet_pton(int family, const char *strptr, void *addrptr); 
//转换字符串到网络地址 。 返回:1成功;-1出错  


const char* inet_ntop(int family, const void *addrptr, char *strptr, size_t len);  
//转换网络二进制结构到ASCII类型的地址
//返回:成功,指向结果的指针;出错,NULL 

3、基于TCP网络编程函数

头文件:#include <sys/types.h>

              #include <sys/socket.h>

(1)bind():将一个本地地址与一套接口捆绑。本函实用与未连接的数据报或流类套接口,在connect()或listen()调用前实用。当socket()创建套接口后,它便存在于一个名字空间(地质簇)中,但并未赋名。bind()函数通过给一个未命名套接口分配一个本地地址名字来为套接口建立本地捆绑(主机地址/端口号)

int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
/*
参数描述:
    sockfd:表示已经建立的socket描述符
    my_addr:是一个指向sockaddr结构体类型的指针
    addrlen:表示my_addr结构的长度,可以用sizeof获得
*/

 通过bind()给socdfd建立三元组(ip、端口、套接口)

(2)listen():创建一个套接口监听申请的连接

int listen( int sockfd, int backlog);
/*
参数描述:
    sockfd:用于标识一个已捆绑未连接套接口的描述字。
    backlog:等待连接队列的最大长度。
*/

 通过listen()给sockfd建立监听窗口

(3)accept()函数将响应连接请求,建立连接(服务器端被动倾听)

int accept( int sockfd , struct sockaddr *addr , int *addrlen);
/*
参数说明:

    sockfd: 被动倾听的socket描述符(服务器端),该套接口在listen()后监听连接,如果连接成功,
            返回一个新的socket描述符(connected socket descriptor)来描述该连接。
            这个连接用来与特定的Client交换信息


    addr:指针,指向一缓冲区,其中接收为通讯层所知的连接实体(客户端)的地址。
          addr参数的实际格式由套接口创建时所产生的地址簇确定。
          addr将在函数调用后被填入连接对方的地址信息,如对方的IP、端口等。

    addrlen:指针,输入参数,配合addr一起使用,指向存有addr地址长度的整型数
*/

 通过accept() 给socket建立完整的五元组

 

(4)connect():初始化一个客户端socket连接到服务器

int connect(int sockfd, struct sockaddr *servaddr, int addrlen);
/*
输入参数:
    socketfd:主动连接的socket描述符(客户端),通过建立的连接与Server交换信息

    servaddr:是事先填写好的结构,Server的IP和端口都在该数据结构中指定

    addrlen:输入参数,配合addr一起使用,存有addr地址长度的整型数
*/

(5)send()/recv():客户端与服务器之间的数据交换

int send(int s, const void *msg, size_t len, int flag);
/*
输入参数:
    s:发送数据的套接口文件描述符。 
    msg:发送的数据的指针 
    len:数据的字节长度 
    flag:标志设置为0。 
*/

int recv(int s, void *buf, size_t len, int flag);
/*
输入参数:
    s:读取的套接口文件描述符。 
    buf:保存读入信息的地址。
    len:缓冲区的最大长度。 
    flag:设置为0。
*/

(6)close():关闭一个socket套接口

int close(int sockfd);
/*
sockefd:要关闭的套接口描述符
*/

4、TCP连接过程

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值