当前位置:首页 > CN2资讯 > 正文内容

在Windows服务器上搭建代码仓库

2天前CN2资讯


一、服务器端

   作为服务器端,要想使客户端能够正常访问,必须有自己的地址,使客户端能够在网络中找到该服务器,就相当于在茫茫人海中想和某人交流,必须知道她在哪儿。与此同时,两个人找到了语言不通也无法进行交流,服务器和客户端的进程亦是如此,不使用相同的协议也无法进行通信,因此服务器端需指定所使用的协议。当两个人相遇之后,还有必不可少的一步就是确认身份,在服务器和客户端通信过程中,客户端在网络中找到了服务器端,必须得到服务器端的接受(建立连接)才可进行通信。这一系列操作完成之后两个人方可你一言我一语(接收信息、发送信息)愉快的交流,最后交流结束两人互相告别,即为释放连接的操作。

    在客户端寻址服务器的时候还可以进一步进行划分,客户端可以通过ip地址在网络中找到服务器主机的位置,但是在一台主机上可能运行着很多进程,而客户端需要通信的可能只是其中的某一个进程或应用程序,因此还需进一步寻址,找到要建立通信的进程,这就需要知道该进程的端口号,客户端可以通过端口号找到具体的进程。

具体流程如下:

  • socket() 创建套接字:指定底层协议族;指定服务类型。
  • bind() 命名socket:指定服务器ip地址并告诉计算机我要使用某个端口。
  • listen() 监听socket:建立一个监听序列以存放待处理的客户连接。
  • accept() 处理连接,从监听队列中接受一个连接。
  • recv() send() 客户端与服务器进行通信。
  • close() 通信完成,断开连接。 
  • 二、客户端

      客户端访问服务器,也必须按照服务器的协议进行操作,因此客户端需指定本身所使用的底层协议和服务器相同(即上例中的语言相通)。接下来就是客户端在网络中找服务器,给定客户端服务器的ip地址和具体进程或应用程序的端口号,客户端即可找到服务器。客户端找到服务器之后就申请建立连接,等待服务器接受连接之后,客户端便可与服务器进行通信。最后通信结束关闭连接。

    具体流程如下:

  • socket() 创建socket,功能和服务器相同
  • connect() 申请连接:需指定服务器ip地址和相关进程的端口号
  • send() recv( ) 进行通信
  • close() 关闭连接
  • 三、步骤详解

    1、创建套接字

          为了执行网络I/O,一个进程必须做的第一件事就是调用socket函数,指定期望的通信协议类型。在unix/linux操作系统中,一切皆文件,socket也不例外它就是可读可写而控制可关闭的文件描述符。以下是创建socket的系统调用。

    # include<sys/types.h> # include<sys/stat.h> int socket(int domain, int type, int protocol); domain参数:指定底层协议族。 tcp/ip:PF_INET(ipv4) PF_INET6(ipv6) unix本地域协议族:PF_UNIX type参数:指定服务类型 SOCK_STREAM:流式服务(遵守tcp服务) SOCK_UGRAM:数据报服务(遵守udp服务) protocol:恒置0

    2、命名socket

      创建socket时,我们给它指定了地址族,但是并未指定使用该地址族中的哪个具体socket地址。将一个socket与socket地址绑定称为给socket命名。服务器端只有命名后客户端才能知道该如何连接它,客户端通常不需要命名socket,而是采用匿名的方式,即使用操作系统自动分配的socket。命名socket用bind()系统调用。

    # include<sys/types.h> # include<sys/stat.h> int bind(int sockfd, const struct struct sockaddr *myaddr, socklen_t addrlen); bind将my_addr所指的socket地址分配给未命名的sockfd文件描述符,addrlen参数指出socket地址长度,成功返回0,失败返回-1; socket地址分为通用socket地址和专用socket地址: 通用socket地址: # include<bits/socket.h> struct sockaddr { sa_family_t; //地址族类型(与协议族一一对应) char sa_data[14]; //存放socket地址值 } 专用socke地址: 1、UNIX本地域协议族专用socket地址 # include<sys/un.h> struct sockaddr_un { sa_family_t sin_family; //地址族,AF_UNIX char sun_path[108]; // 文件路径名 } 2、tcp/ip协议族有sockaddr_in和sockaddr_in6两个专用socket地址结构体,他们分别用于ipv4和ipv6 struct sockaddr_in { sa_family sin_family; //地址族,AF_INET u_int16_t sin_port; //端口号,要用网络字节序表示 struct in_addr sin_addr; //ipv4地址结构体 } struct in_addr { u_int32_t s_addr; //ipv4地址,要用网络字节序表示 } struct sockaddr_in6 { sa_family_t sin6_family; //地址族,AF_INET6 u_int16_t sin6_port; //端口号,要用网络字节序表示 u_int32_t sin6_flowinfo; //流信息,应设置为0 struct int6_addr sin6_addr; //ipv6地址结构体 u_int32_t sin6_scope_id; } struct in6_addr { unsigned char sa_addr[16]; //ipv6地址,要用网络字节序表示 }

    协议族和地址族的关系

    协议族

    地址族

    描述

    PF_UNIX

    AF_UNIX

    UNIX本地域协议族

    PF_INET

    AF_INET

    tcp/ipv4协议族

    PF_INET6

    AF_INET6

    tcp/ipv6协议族

    3、监听socket

    socket被命名之后,还不能马上接受客户连接,我们需要使用系统调listen用来创建一个监听队列以存放待处理的客户连接,listen系统调用有做两件事:

    • 当函数socket创建一个套接口时,它假设为一个主动套接口,也就是说,它是一个将调用connect发起连接的客户套接口,函数listen将未连接的套接口转换成被动套接口,指示内核应接受指向套接口的连接请求。调用函数listen导致套接口从CLOSED状态转换到LISTEN状态
    • 函数第二个参数在linux和unix系统中有所差异,具体如下:

          为了理解参数backlog,我们必须明白,对于给定的监听套接口,内核需要维护两个队列:(1)未完成连接队列,为每个这样的SYN分节开设一个条目:已由客户发出并到达服务器,服务器正在等待完成相应的TCP三次握手过程。这些套接口都处于SYN_RCV状态。(2)已完成连接队列,为每个已完成TCP三次握手过程的客户开设一个条目。这些套接口都处于ESTABLISHED状态。

          在linux系统中,backlog参数是以上两个队列和的最大值,在unix系统中,backlog参数是已完成三次握手的队列(也就是上边提到的第二个队列)的最大值。

    # include<sys/socket.h> int listen(int sockfd, int backlog); 参数sockfd:指被监听的socket

    4、接受连接

    接受连接是指从listen监听队列中接受一个连接,若已完成三次握手的队列为空,则进程阻塞。

    # include<sys/types.h> # include<sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) 参数sockfd:执行过listen系统调用的监听socket 参数addr:用来获取被接受连接的远端socket地址 参数adrlen:socket地址的长度 返回值:成功返回一个新的连接socket,该socket唯一的标识了被接受的这个连接,服务器可以通过读写该socket来与被接受连接对应的客户端通信;失败返回-1

    5、发起连接

    如果说服务器通过listen调用来被动接受连接,那么客户端需要通过如下系统调用主动与服务器建立连接

    # include<sys/types.h> # include<sys/socket.h> int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen); 参数sockfd:由socket系统调用返回一个socket 参数ser_addr:服务器监听的socket地址 参数addrlen:指定服务器监听的socket地址的长度

    6、关闭连接

    关闭一个连接实际上就是关闭该连接对应的socket,这可以通过如下关闭普通文件描述符的系统调用来完成。

    # include<unistd.h> int close(int fd); fd参数是一个待关闭的socket,close系统调用并非总是立即关闭一个连接,而是将fd的引用计数器减1. 只有当fd的引用计数器为0时,才是真正关闭连接。 多进程中,一次fork系统调用默认将使父进程中打开的socket的引用计数加1, 因此我们必须在父进程和子进程中都对该socket执行close调用才能将连接关闭。

    7、数据接受和发送

    对文件的读写操作read和write同样适用于socket,但是socket编程接口提供了几个专门用于socket数据读写的系统调用,以tcp流诗句读写为例:

    # include<sys/types.h> # incldue<sys/socket.h> ssize_t recv(int sockfd, void *buf, size_t len, int flags); ssize_t send(int sockfd, const void *buf, size_t len, int flags);

    四、代码

    服务器端:

    # include<stdio.h> # include<stdlib.h> # include<unistd.h> # include<string.h> # include<assert.h> # include<sys/socket.h> # include<netinet/in.h> # include<arpa/inet.h> int main() { //创建socket //设置网络编程接口 //AF_INET表示TCP/IPv4协议族 //SOCK_STREAM表示流式服务 //0 表示默认协议,几乎所有情况都置0 int sockfd = socket(AF_INET, SOCK_STREAM, 0); assert(sockfd != -1); //定义socket地址类型结构体 struct sockaddr_in saddr, caddr; //ipv4专用socket地址类型结构 memset(&saddr, 0, sizeof(saddr));//将socket置空 //设置socket地址信息 saddr.sin_family = AF_INET;//指明接口协议族类型 saddr.sin_port = htons(6000);//指明服务器端口号 saddr.sin_addr.s_addr = inet_addr("127.0.0.1");//指明服务器IP地址 //inet_addr函数用于把点分十进制转换为用ipv4网络字节序表示的ipv4地址 //给创建的socket分配地址,ip地址、端口号等,即将sockfd与saddr绑定 int res = bind(sockfd,(struct sockaddr*)&saddr, sizeof(saddr)); assert(res != -1); listen(sockfd, 5);//监听socket //5表示监听队列最大长度 while(1) { int len = sizeof(caddr); int c = accept(sockfd, (struct sockaddr*)&caddr, &len);//接收连接 csddr用来存储被接受连接的客户端socket地址 if(c < 0) { continue; } char buff[128] = {0}; recv(c, buff, 127, 0);//读取sockfd上的数据,读取到buff缓冲区中,缓冲区大小为127 printf("buff = %s\n", buff); send(c, "ok", 2, 0);//发送数据给被接受连接端(客户端) close(c);//关闭连接 } }

    客户端:

    # include<stdio.h> # include<stdlib.h> # include<unistd.h> # include<assert.h> # include<string.h> # include<sys/socket.h> # include<netinet/in.h> # include<arpa/inet.h> int main() { //创建socket int sockfd = socket(AF_INET, SOCK_STREAM, 0); assert(sockfd != -1); //设置服务器端socket地址 struct sockaddr_in saddr; memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = htons(6000); saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //建立连接 int res = connect(sockfd, (struct sockaddr*)&saddr, sizeof(saddr)); assert(res != -1); char buff[128] = {0}; printf("input:\n"); fgets(buff, 128, stdin); //发送消息 send(sockfd, buff, strlen(buff), 0); memset(buff, 0, 128); //接收消息 recv(sockfd, buff, 127, 0); printf("buff = %s\n", buff); //关闭连接 close(sockfd); }

     

     

      你可能想看:

      扫描二维码推送至手机访问。

      版权声明:本文由皇冠云发布,如需转载请注明出处。

      本文链接:https://www.idchg.com/info/31091.html

      分享给朋友:

      “在Windows服务器上搭建代码仓库” 的相关文章

      VPS是什么?全面解析虚拟专用服务器的定义、用途与选择指南

      VPS的定义 VPS,全称Virtual Private Server,中文翻译为虚拟专用服务器。它是一种通过虚拟化技术将一台物理服务器分割成多个独立虚拟服务器的服务。每个VPS都拥有自己的操作系统、存储空间、内存和带宽,用户可以像使用独立服务器一样进行管理和配置。VPS的出现,为用户提供了一种介于...

      ITLDC:高性价比的VPS云服务器解决方案

      ITLDC是一家成立于1995年的保加利亚服务器提供商,算得上行业里的“老前辈”。凭借着超过20年的运营历史,ITLDC在服务器供应行业中积累了丰富的经验,虽然其低调的运营风格让它并不算是家喻户晓的品牌,但它所提供的服务种类相当齐全,包括VPS云服务器、虚拟主机、独立服务器、DDoS防御、SSL证书...

      CloudCone VPS评测:高性能与灵活计费方案的完美结合

      在谈论CloudCone VPS之前,让我给你介绍一下这家服务商。CloudCone成立于2017年,起源于美国,主要是在洛杉矶的MultaCom机房提供云主机和VPS服务。自创立以来,CloudCone逐步发展壮大,不断优化和提升其服务质量,为用户提供便捷的云计算解决方案。可以说,CloudCon...

      国外常用ping工具及其使用方法

      ping工具在国外的应用 什么是ping工具?其基本功能和重要性 ping工具是一种非常实用的网络诊断工具,通过向指定的IP地址发送数据包来检测网络连接的质量。当我们在互联网上进行访问时,ping工具能够帮助我们了解网络延迟、丢包率等关键指标。这些信息对于网站运营者和普通用户来说都是极其重要的,因为...

      水牛VPS:高性能虚拟专用服务器的最佳选择与比较

      水牛城VPS,顾名思义,是在美国纽约州布法罗市托管的虚拟专用服务器。这种服务器因其独特的地理位置和优越的技术配置,吸引了众多用户,特别是需要高性能和灵活性的网站和应用程序。这类服务的定义非常简单,但其特点却非常丰富。通常来说,水牛城VPS提供了良好的网络带宽、灵活的存储选项,以及能够根据用户需求进行...

      如何选择国内免费服务器?全面指南与推荐

      国内免费服务器概述 在当今数字化快速发展的时代,云计算的普及正以前所未有的速度改变着我们的工作和生活方式。国内云服务器市场也随着这股潮流不断壮大,越来越多的云服务提供商进入市场,尝试用优惠的价格吸引用户。尤其是对于那些刚起步的开发者和小型企业而言,国内免费服务器的出现无疑为他们提供了一个很好的机会。...