socket编程--相关函数

socket编程–相关函数

1.socket函数
头文件:

#include <sys/types.h>          
#include <sys/socket.h>

1)函数原型

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

2)函数功能
创建一个套接字,并返回一个文件描述符;
3)函数参数
domain
协议家族
AF_INET : IPv4协议
AF_INET6: IPv6协议

type:
数据传输方式/套接字类型,常用的有 SOCK_STREAM(流格式套接字/面向连接的套接字和 SOCK_DGRAM(数据报套接字/无连接的套接字)

protocol:
表示传输协议,常用的有 IPPROTO_TCP 和 IPPROTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议。
说明:
如果使用 SOCK_STREAM 传输数据,那么满足这两个条件的协议只有 TCP,因此可以这样来调用 socket() 函数:

int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  //IPPROTO_TCP表示TCP协议

这种套接字称为 TCP 套接字。

如果使用 SOCK_DGRAM 传输方式,那么满足这两个条件的协议只有 UDP,因此可以这样来调用 socket() 函数:

int udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);  //IPPROTO_UDP表示UDP协议

这种套接字称为 UDP 套接字。

2. bind()函数

socket() 函数用来创建套接字,确定套接字的各种属性,然后服务器端要用 bind() 函数将套接字与特定的 IP 地址和端口绑定起来,只有这样,流经该 IP 地址和端口的数据才能交给套接字处理。
头文件

#include <sys/types.h>          
#include <sys/socket.h>

1)函数原型

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

2)参数:

sockfd:socket 文件描述符

addr: sockaddr 结构体变量的指针

addrlen:addr变量的大小 可以使用sizeof()计算得出.

3)sockaddr_in 结构体

struct sockaddr_in{
  sa_family_t     sin_family;   //地址族(Address Family),也就是地址类型
  uint16_t        sin_port(2);     //16位的端口号
  struct in_addr  sin_addr(4);     //32位IP地址
  char            sin_zero[8];  //不使用,一般用0填充
    		};

sin_family 和 socket() 的第一个参数的含义相同,取值也要保持一致

sin_prot 为端口号。uint16_t 的长度为两个字节,理论上端口号的取值

范围为 0~65536,但 0~1023 的端口一般由系统分配给特定的服务程序,

4) sockaddr结构体

struct sockaddr {
  sa_family_t sa_family; //地址族(Address Family),也就是地址类型
  char        sa_data[14]; //IP地址和端口号
           }

5)in_addr 结构体
sockaddr_in 的第3个成员是 in_addr 类型的结构体,该结构体只包含一个成员,如下所示:

 struct in_addr{
   in_addr_t  s_addr;  //32位的IP地址
    	};

为什么使用 sockaddr_in 而不使用 sockaddr?
sockaddr 与 sockaddr_in 的对比(括号中的数字表示所占用的字节数)
在这里插入图片描述

sockaddr 和 sockaddr_in 的长度相同,都是16字节,只是将IP地址和端口号合并到一起,用一个成员 sa_data 表示。要想给 sa_data 赋值,必须同时指明IP地址和端口号.,例如”127.0.0.1:80“,遗憾的是,没有相关函数将这个字符串转换成需要的形式,也就很难给 sockaddr 类型的变量赋值,所以使用 sockaddr_in 来代替。这两个结构体的长度相同,强制转换类型时不会丢失字节,也没有多余的字节。

3. connect函数

1)函数原型

#include <sys/types.h>      
#include <sys/socket.h>
 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

2)函数的功能
建立连接;
3)函数参数
和bind()一样
4)返回值
连接成功,返回0,连接失败返回-1 errorno被设置.

4.listen函数

1)函数原型

#include <sys/types.h>   
#include <sys/socket.h>
 int listen(int sockfd, int backlog);

2)函数功能
让套接字进入被动监听状态
3)函数参数
sockfd
需要进入监听状态的套接字
backlog
请求队列的最大长度。

请求队列
当套接字正在处理客户端请求时,如果有新的请求进来,套接字是没法处理的,只能把它放进缓冲区,待当前请求处理完毕后,再从缓冲区中读取出来处理。如果不断有新的请求进来,它们就按照先后顺序在缓冲区中排队,直到缓冲区满。这个缓冲区,就称为请求队列(Request Queue)。

缓冲区的长度(能存放多少个客户端请求)可以通过 listen() 函数的 backlog 参数指定,但究竟为多少并没有什么标准,可以根据你的需求来定,并发量小的话可以是10或者20。

如果将 backlog 的值设置为 SOMAXCONN,就由系统来决定请求队列长度,这个值一般比较大,可能是几百,或者更多。

当请求队列满时,就不再接收新的请求,对于 Linux,客户端会收到 ECONNREFUSED 错误,对于 Windows,客户端会收到 WSAECONNREFUSED 错误。

注意:listen() 只是让套接字处于监听状态,并没有接收请求。接收请求需要使用 accept() 函数。
***4)返回值
连接成功,返回0,连接失败返回-1 errorno被设置

5.accept函数

1)函数原型

#include <sys/types.h>        
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

2)函数功能
当套接字处于监听状态时,可以通过 accept() 函数来接收客户端请求
3)函数参数
和bind(),connect()一样.
accept() 返回一个新的套接字来和客户端通信,addr 保存了客户端的IP地址和端口号,而 sockfd 是服务器端的套接字.
listen() 只是让套接字进入监听状态,并没有真正接收客户端请求,listen() 后面的代码会继续执行,直到遇到 accept()。accept() 会阻塞程序执行(后面代码不能被执行),直到有新的请求到来。

6 .write函数

两台计算机之间的通信相当于两个套接字之间的通信,在服务器端用 write() 向套接字写入数据,客户端就能收到,然后再使用 read() 从套接字中读取出来,就完成了一次通信。

 #include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

//向套接字中写入数据
fd 为要写入的文件的描述符,buf 为要写入的数据的缓冲区地址,count 为要写入的数据的字节数。

7 .read函数

1)函数原型

#include <unistd.h>
ssize_t read(int fd, void *buf,size_t count);

2)函数功能
从套接字中读取数据
fd 为要写入的文件的描述符,buf 为要写入的数据的缓冲区地址,count为要写入的数据的字节数。
read() 函数会从 fd 文件中读取 count 个字节并保存到缓冲区 buf,成功则返回读取到的字节数(但遇到文件结尾则返回0),失败则返回 -1。

8 其他相关函数
1)memset函数

#include <string.h>
void *memset(void *s, int c, size_t n);
//将目标字符串指定数目的字节置为 c

2)memcpy函数

#include <string.h>
 void *memcpy(void *dest, const void *src, size_t n);
 //将指定数目的字节从源字节复制到目标字节

3)memcmp函数

#include <string.h>
int memcmp(const void *s1, const void *s2, size_t n);
//比较两个字符串前n个字节大小 相同返回0,不同返回非零

4)inet_aton函数

#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
//将cp指向的字符串转换成32位的网络字节序二级制值 ,结果存储在inp中字
//符串有效返回 1 否则 0

5)inet_pton函数

 #include <arpa/inet.h>
 int inet_pton(int af, const char *src, void *dst);
/*******************************************************
 转换src为一个网络地址结构体
 af:AF_INET
 	dst是struct in_addr
 af:AF_INET6
 	dst是struct in_addr6
 //尝试转换由src指向的字符串,并将二进制结果保存在dst中
 ******************************************************/
 /******************************************************
 *af :
 	AF_INET :
 		src指向一个点分十进制的网络地址 "ddd.ddd.ddd.ddd"
 		d的范围为0~255;
 		这个地址别转换成 struct in_addr类型,并且被复制到dst中
 		dst的大小必须是sizeof(struct in_addr)
 	AF_INET6:
 		指向一个IPv6的网络地址
 		格式是:x:x:x:x:x:x:x:x.每个x可以增加到4位16进制*
 		*******************************************************/ 	

6)inet_ntop函数

#include <arpa/inet.h>
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
//将src从数值格式转换成表达式格式,并存放在dst中.size是dst的大小
//af:地址家族,和inet_pton
//成功 返回一个指向dst的非空指针 出错 返回NULL errno被设置
/********************************************************
转换网络地址结构体src为字符串,转换的结果被复制到dst中,
size指定缓冲区的大小
********************************************************/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值