TCP网络编程

部分内容转载:C语言网络编程:accept函数详解_z_stand的博客-CSDN博客_c语言accept函数

1、先看一张图

在这里插入图片描述

 2、各个函数详解

1)accept函数

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
函数功能:
被动监听客户端发起的tcp连接请求,三次握手后连接建立成功。客户端connect函数请求发起连接。
连接成功后服务器的tcp协议会记录客端的ip和端口,如果是跨网通信,记录ip的就是客户端所在路由器的公网ip
返回值:
成功:返回一个通信描述符,专门用于与连接成功的客户端进行通信。
失败:返回-1 ,并设置errno
函数参数:
a. sockfd 已经被listen转为了被动描述符的“套接字文件描述符”,专门用于客户端的监听,入股sockfs没有被listen函数转为被动描述符,则accept是无法将其用来监听客户端连接的。
套接字文件描述符默认是阻塞的,即如果没有客户端请求连接的时候,此时accept会阻塞,直到有客户端连接;如果不想套接字文件描述符阻塞,则可以创建套接字 socket函数 时指定type为SOCK_NOBLOCK
b. addrlen表示第二个参数addr的大小,不过要求给定地址
c. addr: 用于记录发起连接请求的那个客户端的IP端口
建立连接时服务器的TCP协议会自动解析客户端发来的数据包,从中获取客户端的IP和端口号
这里如果服务器应用层需要用到客户端的 IP和端口号,可以给accept指定第二个参数addr,以获取TCP链接时的客户端ip和端口号;如果服务器应用层不需要,则写NULL即可
addr的结构体类型为 struct sockaddr,在listen函数详解中我们有介绍过,由于这个结构体用起来不是非常方便,我们需要定义struct sockaddr_in结构体来使得sockaddr结构体操作更为便捷。具体使用如下:
struct sockaddr_in naddr = {0};
 
int nsize = sizeof(naddr);
int cfd = accept(sockfd, (struct sockaddr *)&naddr, &nsize);
 

使用下列代码可以打印客户端的ip和端口信息:

struct sockaddr_in caddr = {0};

int csize = sizeof(caddr);
cfd = accept(sockfd, (struct sockaddr *)&caddr, &csize);

printf("cport = %d, caddr = %s\n", ntohs(caddr.sin_port),inet_ntoa(caddr.sin_addr));

3、示例代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>

void print_err(char *str, int line, int err_no) {
	printf("%d, %s :%s\n",line,str,strerror(err_no));
	_exit(-1);
}

int main()
{
	int skfd = -1, ret = -1;
	skfd = socket(AF_INET, SOCK_STREAM, 0);
	if ( -1 == skfd) {
		print_err("socket failed",__LINE__,errno);
	}

	struct sockaddr_in addr;
	addr.sin_family = AF_INET; //设置tcp协议族
	addr.sin_port = 6789; //设置端口号
	addr.sin_addr.s_addr = inet_addr("192.168.102.169"); //设置ip地址

	ret = bind(skfd, (struct sockaddr*)&addr, sizeof(addr));
	if ( -1 == ret) {
		print_err("bind failed",__LINE__,errno);
	}
 
 	/*将套接字文件描述符从主动转为被动文件描述符,然后用于被动监听客户端的连接*/
	ret = listen(skfd, 3);
	if ( -1 == ret ) {
		print_err("listen failed", __LINE__, errno);
	}

	/*被动监听客户端发起的tcp连接请求,三次握手后连接建立成功*/
	int cfd = -1;
	struct sockaddr_in caddr = {0}; //为应用层获取客户端的IP和端口号
	int csize = 0;
	cfd = accept(skfd, (struct sockaddr*)&caddr, &csize);
	if (-1 == cfd) {
		print_err("accept failed", __LINE__, errno);
	}
	
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值