socket

本文介绍了网络编程中的关键函数,包括socket用于创建网络通信端口,listen设置监听状态和最大连接队列,以及accept接受客户端连接。讲解了参数含义和使用场景,并展示了如何使用socketInit函数初始化服务器套接字。涉及TCP/IP协议、地址绑定、端口使用等概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1)、socket

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


 socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调用出错则返回-1。对于IPv4,family参数指定为AF_INET。对于TCP协议,type参数指定为SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定SOCK_DGRAM,表示面向数据报的传输协议。protocol参数的介绍从略,指定为0即可。

2)、listen

int listen(int sockfd, int backlog);


 典型的服务器程序可以同时服务于多个客户端,当有客户端发起连接时,服务器调用的accept()返回并接受这个连接,如果有大量的客户端发起连接而服务器来不及处理,尚未accept的客户端就处于连接等待状态,listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态,如果接收到更多的连接请求就忽略。listen()成功返回0,失败返回-1。

3)、accept

int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);


三方握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。cliaddr是一个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是一个传入传出参数(value-result argument),传入的是调用者提供的缓冲区cliaddr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)。如果给cliaddr参数传NULL,表示不关心客户端的地址。

bind()函数介绍

       在建立套接字文件描述符成功后,需要对套接字进行地址和端口的绑定,才能进行数据的接收和发送操作。

函数原型

       bind()函数将长度为addlen的struct sockadd类型的参数my_addr与sockfd绑定在一起,将sockfd绑定到某个端口上,如果使用connect()函数则没有绑定的必要。绑定的函数原型如下:

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

bind()函数有3个参数。

  • 第1个参数sockfd是用socket()函数创建的文件描述符。

  • 第2个参数my_addr是指向一个结构为sockaddr参数的指针,sockaddr中包含了地址、端口和IP地址的信息。在进行地址绑定的时候,需要弦将地址结构中的IP地址、端口、类型等结构struct sockaddr中的域进行设置之后才能进行绑定,这样进行绑定后才能将套接字文件描述符与地址等接合在一起。

  • 第3个参数addrlen是my_addr结构的长度,可以设置成sizeof(struct sockaddr)。使用sizeof(struct sockaddr)来设置套接字的类型和其对已ing的结构。
    bind()函数的返回值为0时表示绑定成功,-1表示绑定失败,errno的错误值如表1所示。

表1 bind的errno值及含义

含义备注
EADDRINUSE给定地址已经使用
EBADFsockfd不合法
EINVALsockfd已经绑定到其他地址
ENOTSOCKsockfd是一个文件描述符,不是socket描述符
EACCES地址被保护,用户的权限不足
EADDRNOTAVAIL接口不存在或者绑定地址不是本地UNIX协议族,AF_UNIX
EFAULTmy_addr指针超出用户空间UNIX协议族,AF_UNIX
EINVAL地址长度错误,或者socket不是AF_UNIX族UNIX协议族,AF_UNIX
ELOOP解析my_addr时符号链接过多UNIX协议族,AF_UNIX
ENAMETOOLONGmy_addr过长UNIX协议族,AF_UNIX
ENOENT文件不存在UNIX协议族,AF_UNIX
ENOMEN内存内核不足UNIX协议族,AF_UNIX
ENOTDIR不是目录UNIX协议族,AF_UNIX
EROFSsocket节点应该在制度文件系统上UNIX协议族,AF_UNIX

封装 socket 初始化函数


int socketInit(struct inputCommand *socketMes)
{

     int s_fd;

	 struct sockaddr_in s_addr;
    memset(&s_addr,0,sizeof(struct sockaddr_in));
	 
	 //1.socket
	s_fd = socket(AF_INET,SOCK_STREAM,0);
		if(s_fd == -1){
			perror("socket");
			exit(-1);
		}

	  s_addr.sin_family = AF_INET;
	  s_addr.sin_port = htons(atoi(socketMes->port));
	  inet_aton(socketMes->ipAdress,&s_addr.sin_addr);
		
	//2.bind
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));

	//3.listen
	listen(s_fd,10);
	printf("socket Server listening ...\n");
	socketMes->fd=s_fd;
	return s_fd;

}

 定义函数:int inet_aton(const char * cp, struct in_addr *inp);

        函数说明:inet_aton()用来将参数cp 所指的网络地址字符串转换成网络使用的二进制的数字, 然后存于参数inp 所指的in_addr 结构中.

  htons的功能:uint16_t htons(uint16_t hostshort); 

将一个无符号短整型数值转换为网络字节序,即大端模式(big-endian)  参数u_short hostshort: 16位无符号整数 返回值:TCP / IP网络字节顺序.
 
  int atoi(const char *str)

把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值