accept函数的参数不是随便填的

本文深入解析Linux套接字API中的accept函数,包括其参数、返回值及实际应用示例,帮助开发者更好地掌握网络编程的核心概念。

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

#include<sys/socket.h>
int accept(int sockfd, struct sockaddr* addr, socklen_t* len)
返回:非负描述字——成功, -1——失败

accept默认会阻塞进程,直到有一个客户连接建立后返回,它返回的是一个新可用的套接字,这个套接字是连接套接字。此时我们需要区分两种套接字,一种套接字正如accept的参数sockfd,它是监听套接字,在调用listen函数之后,一个套接字会从主动连接的套接字变身为一个监听套接字;而accept返回是一个连接套接字,它代表着一个网络已经存在的点点连接。自然要问的是:为什么要有两种套接字?原因很简单,如果使用一个描述字的话,那么它的功能太多,使得使用很不直观,同时在内核确实产生了一个这样的新的描述字。

如果accept成功返回,则服务器与客户已经正确建立连接了,此时服务器通过accept返回的套接字来完成与客户的通信。

参数sockfd

参数sockfd就是上面解释中的监听套接字,这个套接字用来监听一个端口,当有一个客户与服务器连接时,它使用这个一个端口号,而此时这个端口号正与这个 套接字关联。当然客户不知道套接字这些细节,它只知道一个地址和一个端口号。

参数addr

这是一个结果参数,它用来接受一个返回值,这返回值指定客户端的地址,当然这个地址是通过某个地址结构来描述的,用户应该知道这一个什么样的地址结 构。如果对客户的地址不感兴趣,那么可以把这个值设置为NULL。

参数len

如同大家所认为的,它也是结果的参数,用来接受上述addr的结构的大小的,它指明addr结构所占有的字节个数。同样的,它也可以被设置为NULL。

但是,如果你给accept函数第2和第3个参数赋值后,就要记得“用之”,否则就会报错。

举个简单的例子

客户端程序都相同,如下:

#include <stdio.h>
#include <string.h>//memset strlen
#include <stdlib.h>

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

#include <ctime>
#include <arpa/inet.h>

/*
unistd.h 中所定义的接口通常都是大量针对系统调用的封装(英语:wrapper functions)
如 fork、pipe 以及各种 I/O 原语(read、write、close 等等)
*/
#include <unistd.h>

#include <wait.h>

#define MAX_STR 256
int main(){
	
	char buf[MAX_STR];
	char succ[]="success";
	char fail[]="failed";

	int clientFd;
	clientFd=socket(AF_INET,SOCK_STREAM,0);//0:按给定的域和套接字类型选择默认协议
	
	struct sockaddr_in serverAddr;
	memset(&serverAddr,0,sizeof(serverAddr));
	serverAddr.sin_family=AF_INET;
	serverAddr.sin_port=htons(12345);
	serverAddr.sin_addr.s_addr=inet_addr("127.0.0.1");
	
	printf("Socket has been created.\n");
	
	int cRes=connect(clientFd,(struct sockaddr*)&serverAddr,sizeof(serverAddr));
	
	//判断是否成功
	if(cRes<0){
		printf("fail to connect\n");
		exit(1);
	}else{
		printf("connect success!\n");
		
	}
	int recvLen=recv(clientFd,(void*)buf,MAX_STR,0);
	if(recvLen>0){
		printf("recv success:\n");
		printf("recv: %s\n",buf);
		send(clientFd,(void*)succ,strlen(succ),0);//不接受带外数据,阻塞式,可将数据路由出本地网络
	}else{
		printf("fail to recv the server's data\n");
		send(clientFd,(void*)fail,strlen(fail),0);
	}
	close(clientFd);
    	printf("Now the connection has been broken\n");
    	close(clientFd);
	
	
	return 0;
}


服务端1:
acceptFd = accept(serverFd,(struct sockaddr*)&clientAddr,(socklen_t*)&clientLen);

后续程序中使用到了clientAddr,clinetLen,程序没有问题

#include <stdio.h>
#include <string.h>//memset strlen
#include <stdlib.h>

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

#include <ctime>
#include <arpa/inet.h>

/*
unistd.h 中所定义的接口通常都是大量针对系统调用的封装(英语:wrapper functions)
如 fork、pipe 以及各种 I/O 原语(read、write、close 等等)
*/
#include <unistd.h>

#include <wait.h>

#define MAX_STR 256
int count=0;
int main(){
	
	char buf[MAX_STR];
	char sayHello[]="Good morning Mr S!";
	int serverFd;
	serverFd=socket(AF_INET,SOCK_STREAM,0);
	
	int acceptFd;	

	struct sockaddr_in clientAddr;
	int clientLen;

	struct sockaddr_in serverAddr;
	memset(&serverAddr,0,sizeof(serverAddr));
	serverAddr.sin_family=AF_INET;
	serverAddr.sin_port= htons(12345);
	serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);
	
	bind(serverFd,(sockaddr*)&serverAddr,sizeof(serverAddr));
	
	printf("Socket has been created and bind\n");
	
	listen(serverFd,5);
	
	
	  while(true)
    {
		printf("--------------------------%d\n",count++);
	
		printf("Now listening...\n");
		/* 接受客户端申请的连接 */
		acceptFd = accept(serverFd,(struct sockaddr*)&clientAddr,(socklen_t*)&clientLen);

		/* 如果client成功连接到server, 则执行 */
		if(acceptFd >= 0){
			printf("Now the link has been connected.\n");

			/* 从客户端的套接字中提取出IP地址 和其他信息*/
			int clientip = clientAddr.sin_addr.s_addr;
			printf("Client ip : %d.%d.%d.%d\n",clientip&255,(clientip>>8)&255,
					(clientip>>16)&255,(clientip>>24)&255);
			printf("Client prot : %d\n",ntohs(clientAddr.sin_port));



			/* 使用send向client发送信息 */
			sprintf(buf,"THE SEND MSG");

			printf("[SEND] Starting sending [send] msg ...\n");

			send(acceptFd, (void*)buf, strlen(buf),0);//发送数据 strlen(buff) bytes数据

			recv(acceptFd, (void*)buf, MAX_STR, 0 );//接收客户端反馈,成功或失败?//MAXN_STR:最大努力接收

			if(strlen(buf) > 0)
				printf("[SUCC] Sending succeed.\n");
			else
				printf("[FAIL] Sending failed.\n");

			/* 关闭此连接 */
			close(acceptFd);
			printf("Disconnect the link.\n");

		}else{
			/*  与client连接失败 */
			printf("ERROR: Failed while establish the link!\n");
		}
    }
	close(serverFd);
	
	return 0;
}


服务端程序2:
acceptFd = accept(serverFd,NULL,NULL);
也没有问题

#include <stdio.h>
#include <string.h>//memset strlen
#include <stdlib.h>

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

#include <ctime>
#include <arpa/inet.h>

/*
unistd.h 中所定义的接口通常都是大量针对系统调用的封装(英语:wrapper functions)
如 fork、pipe 以及各种 I/O 原语(read、write、close 等等)
*/
#include <unistd.h>

#include <wait.h>

#define MAX_STR 256
int count=0;
int main(){
	
	char buf[MAX_STR];
	char sayHello[]="Good morning Mr S!";
	int serverFd;
	serverFd=socket(AF_INET,SOCK_STREAM,0);
	
	int acceptFd;	

	struct sockaddr_in clientAddr;
	int clientLen;

	struct sockaddr_in serverAddr;
	memset(&serverAddr,0,sizeof(serverAddr));
	serverAddr.sin_family=AF_INET;
	serverAddr.sin_port= htons(12345);
	serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);
	
	bind(serverFd,(sockaddr*)&serverAddr,sizeof(serverAddr));
	
	printf("Socket has been created and bind\n");
	
	listen(serverFd,5);
	
	
	  while(true)
    {
		printf("--------------------------%d\n",count++);
	
		printf("Now listening...\n");
		/* 接受客户端申请的连接 */
		acceptFd = accept(serverFd,NULL,NULL);

		/* 如果client成功连接到server, 则执行 */
		if(acceptFd >= 0){
			printf("Now the link has been connected.\n");

			/* 从客户端的套接字中提取出IP地址 和其他信息
			int clientip = clientAddr.sin_addr.s_addr;
			printf("Client ip : %d.%d.%d.%d\n",clientip&255,(clientip>>8)&255,
					(clientip>>16)&255,(clientip>>24)&255);
			printf("Client prot : %d\n",ntohs(clientAddr.sin_port));*/



			/* 使用send向client发送信息 */
			sprintf(buf,"THE SEND MSG");

			printf("[SEND] Starting sending [send] msg ...\n");

			send(acceptFd, (void*)buf, strlen(buf),0);//发送数据 strlen(buff) bytes数据

			recv(acceptFd, (void*)buf, MAX_STR, 0 );//接收客户端反馈,成功或失败?//MAXN_STR:最大努力接收

			if(strlen(buf) > 0)
				printf("[SUCC] Sending succeed.\n");
			else
				printf("[FAIL] Sending failed.\n");

			/* 关闭此连接 */
			close(acceptFd);
			printf("Disconnect the link.\n");

		}else{
			/*  与client连接失败 */
			printf("ERROR: Failed while establish the link!\n");
		}
    }
	close(serverFd);
	
	return 0;
}
但是,如果你使用了
acceptFd = accept(serverFd,(struct sockaddr*)&clientAddr,(socklen_t*)&clientLen);
却没有用之,程序就会报错!可以自己试下如下程序,具体原因不知道,但是恶心是恶心够了。。。
#include <stdio.h>
#include <string.h>//memset strlen
#include <stdlib.h>

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

#include <ctime>
#include <arpa/inet.h>

/*
unistd.h 中所定义的接口通常都是大量针对系统调用的封装(英语:wrapper functions)
如 fork、pipe 以及各种 I/O 原语(read、write、close 等等)
*/
#include <unistd.h>

#include <wait.h>

#define MAX_STR 256
int count=0;
int main(){
	
	char buf[MAX_STR];
	char sayHello[]="Good morning Mr S!";
	int serverFd;
	serverFd=socket(AF_INET,SOCK_STREAM,0);
	
	int acceptFd;	

	struct sockaddr_in clientAddr;
	int clientLen;

	struct sockaddr_in serverAddr;
	memset(&serverAddr,0,sizeof(serverAddr));
	serverAddr.sin_family=AF_INET;
	serverAddr.sin_port= htons(12345);
	serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);
	
	bind(serverFd,(sockaddr*)&serverAddr,sizeof(serverAddr));
	
	printf("Socket has been created and bind\n");
	
	listen(serverFd,5);
	
	
	  while(true)
    {
		printf("--------------------------%d\n",count++);
	
		printf("Now listening...\n");
		/* 接受客户端申请的连接 */
		acceptFd = accept(serverFd,(struct sockaddr*)&clientAddr,(socklen_t*)&clientLen);

		/* 如果client成功连接到server, 则执行 */
		if(acceptFd >= 0){
			printf("Now the link has been connected.\n");

			/* 从客户端的套接字中提取出IP地址 和其他信息
			int clientip = clientAddr.sin_addr.s_addr;
			printf("Client ip : %d.%d.%d.%d\n",clientip&255,(clientip>>8)&255,
					(clientip>>16)&255,(clientip>>24)&255);
			printf("Client prot : %d\n",ntohs(clientAddr.sin_port));*/



			/* 使用send向client发送信息 */
			sprintf(buf,"THE SEND MSG");

			printf("[SEND] Starting sending [send] msg ...\n");

			send(acceptFd, (void*)buf, strlen(buf),0);//发送数据 strlen(buff) bytes数据

			recv(acceptFd, (void*)buf, MAX_STR, 0 );//接收客户端反馈,成功或失败?//MAXN_STR:最大努力接收

			if(strlen(buf) > 0)
				printf("[SUCC] Sending succeed.\n");
			else
				printf("[FAIL] Sending failed.\n");

			/* 关闭此连接 */
			close(acceptFd);
			printf("Disconnect the link.\n");

		}else{
			/*  与client连接失败 */
			printf("ERROR: Failed while establish the link!\n");
		}
    }
	close(serverFd);
	
	return 0;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值