服务器建立TCP通信的基础步骤

关于Linux下的套接字通讯创建流程

在服务器端建立一个套接字通信的之前,我们首先需要建立一个用来进行本地Ip和端口监听的文件描述符。

#include<sys/socket.h>
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
###############################################代码说明######################################################
1.AF_INET:这是地址族(Address Family)的标识符,表示我们使用的是IPv4地址。
2.SOCK_STREAM:这表示套接字的类型。SOCK_STREAM 用于创建TCP套接字。TCP是一个面向连接的、可靠的、基于字节流的传输层协议。
3.0:这是协议号。对于大多数套接字类型,我们可以将其设置为0,这意味着内核将为我们选择合适的协议。

​ <sys/socket.h>这个头文件的位于操作系统的系统库中的文件,他声明了进行网络套接字通信所必要的函数。在上面的代码中,我们函数返回了一个int类型的文件描述符"sockfd"。后续我们将,用这个描述符来绑定我们本地的IP和端口。

接下来我们进行如下操作。

    struct sockaddr_in servaddr;
    servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0
	servaddr.sin_port = htons(2000); // 0-1023, 

	if (-1 == bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr))) {
		printf("bind failed: %s\n", strerror(errno));
	}
//###########################################代码说明########################################################
1.sockaddr_in 是一个结构体,用来记录我们后续要绑定的信息。
2.servaddr.sin_family = AF_INET;
这行代码将servaddr结构体的sin_family字段设置为AF_INET,表明这个地址是IPv4地址。
3.servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0
这行代码设置servaddr的sin_addr字段的s_addr成员。INADDR_ANY是一个特殊的常量,表示服务器愿意接收来自任何IP地址的连接请求。htonl函数用于将主机字节序的长整型数转换为网络字节序。在这里,尽管INADDR_ANY已经是网络字节序,但使用htonl是一个好习惯,以确保代码的一致性和可移植性。
4.servaddr.sin_port = htons(2000); // 0-1023,
这行代码设置servaddr的sin_port字段为2000。htons函数用于将主机字节序的短整型数转换为网络字节序。端口号2000是一个用户定义的端口号,用于服务器监听连接。注意,端口号0到1023是保留给系统或知名服务的,所以通常不建议在这些端口上运行用户应用。
5.接下来的if语句使用bind函数尝试将之前创建的套接字sockfd绑定到servaddr指定的地址和端口上:
6.strerror是C标准库中的函数,用来将当前的错误索引errno描述成错误信息的字符串。

通过上述的操作,我们就可以将“sockfd”这个文件描述符号,与端口2000进行绑定。接下来,我们需要做的就是监听这个窗口的操作。

listen(sockfd, 10);
//###########################################代码说明########################################################
1.sockfd,这是通过 socket() 函数创建的套接字描述符。
2.10,这是等待接受的连接请求的队列长度。换句话说,它指定了尚未被 accept() 函数处理的最大连接数。如果队列已满,新的连接请求将被拒绝。实际允许的最大连接数可能受到系统限制,且可能小于你指定的值。

通过以上的操作,我们就对其fd绑定的端口进行了监听。监听的作用,就是等待客户端发来的连接请求。当客户端输入此计算机的IP和我们绑定的端口号2000,就可以与我们建立TCP连接。但要主要的是,客户端和服务器之间的连接虽然建立了,但是我们还是没有办法对这个连接进行后续的操作,所以我们需要获取一个文件描述符用来维护这段连接。

struct sockaddr_in  clientaddr;
socklen_t len = sizeof(clientaddr);
int clientfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len);

//##########################################代码说明########################################################
1.sockfd是我们刚刚创建的监听本地端口2000的文件描述符。
2.clientaddr是当我们接收了一个新的clientfd文件描述符时候,这个文件描述符所维护的连接对应的客户端的IP和端口等信息。
3.len就是这是一个指向 socklen_t 类型变量的指针,用于在调用时传入 clientaddr 结构体的大小,并在返回时接收实际填充到 clientaddr 中的地址结构的大小。

通过上述操作,我们就成功的建立了一个与客户端进行通信的TCP连接,并且用一个“clientfd‘文件描述符来对其进行维护。我们后续可以调用recv()和send()用来接收和发送这段连接的信息。下面是一段完成流程代码。

#include <errno.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main() {


	int sockfd = socket(AF_INET, SOCK_STREAM, 0);

	struct sockaddr_in servaddr;
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0
	servaddr.sin_port = htons(2000); // 0-1023, 

	if (-1 == bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr))) {
		printf("bind failed: %s\n", strerror(errno));
	}

	listen(sockfd, 10);
	printf("listen finshed\n");

	struct sockaddr_in  clientaddr;
	socklen_t len = sizeof(clientaddr);

 

	printf("accept\n");
	int clientfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len);
	printf("accept finshed\n");

	char buffer[1024] = {0};
	int count = recv(clientfd, buffer, 1024, 0);
	printf("RECV: %s\n", buffer);

	count = send(clientfd, buffer, count, 0);
	printf("SEND: %d\n", count);
	}
  • 21
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值