Computer网络,互连网编制程序

好久没输出了,知识依然要写下总括技能让思绪特别明显。近日在念书Computer网络有关的文化,来聊天怎么着编写叁个建议的HTTP服务器。

一切皆 Socket

在互连网上,通讯服务都是应用C/S机制,也等于客商端/服务器机制。流程可以参谋下图:

其黄金年代http server的兑现源代码笔者放在了我的github上,有意思味的话能够点击查看哦。

咱俩早已知晓网络中的进度是通过 socket 来通信的,那怎么是 socket 呢?

图片 1

HTTP 服务器

HTTP服务器,正是一个运作在主机上的次第。程序运营了后头,会直接在等候别的全体客户端的伏乞,选择到央求之后,管理供给,然后发送响应给顾客端。客商端和服务器之间使用HTTP左券举行通讯,全体服从HTTP公约的主次都足以看作客商端。

先直接上代码,然后再详尽表达完毕细节。

#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#define PORT 9001
#define QUEUE_MAX_COUNT 5
#define BUFF_SIZE 1024

#define SERVER_STRING "Server: hoohackhttpd/0.1.0rn"

int main()
{
    /* 定义server和client的文件描述符 */
    int server_fd = -1;
    int client_fd = -1;

    u_short port = PORT;
    struct sockaddr_in client_addr;
    struct sockaddr_in server_addr;
    socklen_t client_addr_len = sizeof(client_addr);

    char buf[BUFF_SIZE];
    char recv_buf[BUFF_SIZE];
    char hello_str[] = "Hello world!";

    int hello_len = 0;

    /* 创建一个socket */
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("socket");
        exit(-1);
    }
    memset(&server_addr, 0, sizeof(server_addr));
    /* 设置端口,IP,和TCP/IP协议族 */
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    /* 绑定套接字到端口 */
    if (bind(server_fd, (struct sockaddr *)&server_addr,
         sizeof(server_addr)) < 0) {
        perror("bind");
        exit(-1);
    }

    /* 启动socket监听请求,开始等待客户端发来的请求 */
    if (listen(server_fd, QUEUE_MAX_COUNT) < 0) {
        perror("listen");
        exit(-1);
    }

    printf("http server running on port %dn", port);

    while (1) {
        /* 调用了accept函数,阻塞了程序,直到接收到客户端的请求 */
        client_fd = accept(server_fd, (struct sockaddr *)&client_addr,
                   &client_addr_len);
        if (client_fd < 0) {
            perror("accept");
            exit(-1);
        }
        printf("accept a clientn");

        printf("client socket fd: %dn", client_fd);
        /* 调用recv函数接收客户端发来的请求信息 */
        hello_len = recv(client_fd, recv_buf, BUFF_SIZE, 0);

        printf("receive %dn", hello_len);

        /* 发送响应给客户端 */
        sprintf(buf, "HTTP/1.0 200 OKrn");
        send(client_fd, buf, strlen(buf), 0);
        strcpy(buf, SERVER_STRING);
        send(client_fd, buf, strlen(buf), 0);
        sprintf(buf, "Content-Type: text/htmlrn");
        send(client_fd, buf, strlen(buf), 0);
        strcpy(buf, "rn");
        send(client_fd, buf, strlen(buf), 0);
        sprintf(buf, "Hello Worldrn");
        send(client_fd, buf, strlen(buf), 0);

        /* 关闭客户端套接字 */
        close(client_fd);
    }

    close(server_fd);

    return 0;
}

 socket 源点于 UNIX,而 UNIX/Linux 基本经济学之大器晚成正是「一切皆文件」,都能够用「open → write/read → close」格局来操作。 

socket 其实正是该格局的二个落到实处,socket 就是生龙活虎种独特的公文,一些 socket 函数正是对其进行的操作。

劳动器端专门的职业流程:

测量检验运维

代码写好之后,运转测量试验一下,将地点代码保存到server.c,然后编写翻译程序:

gcc server.c -o server

./server运行

图片 2

服务器运转,监听9001端口。再用netstat一声令下查看:
图片 3

server程序在监听9001端口,运营准确。接着用浏览器访谈

图片 4

中标输出了Hello World

再品尝用telnet去模拟HTTP请求:

图片 5

  • 1、成功连接
  • 2、发送HTTP请求
  • 3、HTTP响应结果

地方是贰个最轻易易行的server程序,代码比较轻易,省去一些细节,上面通过代码来学习一下socket的编制程序细节。

行使 TCP/IP 合同的应用程序日常选用系统提供的编制程序接口:UNIX BSD 的套接字接口(Socket Interfaces卡塔 尔(阿拉伯语:قطر‎本条来兑现网络进度之间的通讯。

动用socket()函数创制服务器端通讯套接口

启动server的流程

图片 6

 就当下来说,大概拥有的应用程序都以选用socket,所以说以后的互连网时期,网络中经过通讯是无处不在,一切皆 socket

采纳bind()函数将创制的套接口与服务器地址绑定

socket 函数

创办一个套接字,通过各参数内定套接字的项目。

int socket(int family, int type, int protocol);
  • family:协议族。AF_INET:IPV4协议;AF_INET6:IPv6协议;AF_LOCAL:Unix域协议;AF_ROUTE:路由套接字;AF_KEY:密钥套接字
  • type:套接字类型。SOCK_STREAM : 字节流套接字;SOCK_DGRAM:数据包套接字;SOCK_SEGPACKET:有序分组套接字;SOCK_RAW:原始套接字
  • protocol:有些公约项目常量。TCP:0,UDP :1, SCTP :2

套接字接口 Socket Interfaces

利用listen()函数使劳动器套接口做好选拔延续央浼筹划

套接字地址构造

在socket编制程序中,大部分函数都用到三个指向套接字地址构造的指针作为参数。针对分裂的磋商项目,会有两样的结构体定义格式,对于ipv4,布局如下所示:

struct sockaddr_in {
     uint8_t            sin_len;        /* 结构体的长度 */
     sa_family_t        sin_family;     /* IP协议族,IPV4是AF_INET */
     in_port_t          sin_port;       /* 一个16比特的TCP/UDP端口地址 */
     struct in_addr     sin_addr;       /* 32比特的IPV4地址,网络字节序 */
     char               sin_zero[8];    /* 未使用字段 */
};

注:sockaddr_in是Internet socket address structure的缩写。

套接字接口是风姿罗曼蒂克组函数,由操作系统提供,用以创制网络接受。 大多数今世操作系统都贯彻了套接字接口,饱含持有 Unix 变种,Windows 和 Macintosh 系统。

使用accept()选择来自顾客端由connect()函数发出的连接须要

ip地址布局

struct in_addr {
     in_addr_t      s_addr;
};

套接字地址布局的效劳是为了将ip地址和端口号传递到socket函数,写成结构体的点子是为着架空。当做为叁个参数字传送递进任何套接字函数时,套接字地址构造总是以援用格局传递。然则,左券族有超多,因而以如此的指针作为参数之大器晚成的另衬衫接字函数必得管理来自具有协助的任何合同族的套接字地址构造。使用void *用作通用的指针类型,由此,套接字函数被定义为以指向有些通用套接字构造的三个指南针作为其参数之黄金年代,正如上边包车型客车bind函数原型同样。

int bind(int, struct sockaddr *, socklen_t);

那将须求,对那一个函数的别的调用都不得不要将照准特定于公约的套接字地址构造的指针进行强制类型调换,产生某些通用套接字地址结构的指针。比方:

struct sockaddr_in addr;
bind(sockfd, (struct sockaddr *)&addr , sizeof(addr));

对此具有socket函数来讲,sockaddr的唯朝气蓬勃用项正是对指向性特定商业事务的套接字地址布局的指针实施强制类型变换,指向要绑定给sockfd的说道地址。

套接字接口的源于套接字接口是加州大学Berkeley分校的钻研人口在 20 世纪 80 时期早起提议的。 Berkeley的商量者使得套接字接口适用于别的底层的协商,第二个贯彻正是本着 TCP/IP 交涉,他们把它富含在 Unix 4.2 BSD 的基业里,并且分发给众多学园和实验室。 那在因特网的历史变为了贰个重大事件。 —— 《深刻通晓Computer连串》

基于三番五次诉求创立连接后,使用send()函数发送数据,或然应用recv()函数接收数据

bind函数

将套接字地址结构绑定到套接字

int bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
  • sockfd:socket描述符,唯风度翩翩标记四个socket。bind函数正是将那些描述字绑定一个名字。
  • addr:三个sockaddr指针,指向要绑定给sockfd的议和地址。一个socket由ip和端口号唯黄金时代分明,而sockaddr就包罗了ip和端口的音讯
    地址的长短

绑定了socket之后,就足以行使该socket开首监听央浼了。

从 Linux 内核的角度来看,三个套接字便是通讯的三个端点。 从 Linux 程序的角度来看,套接字是二个有打点描述符的文本。 普通文书的展开操作重回三个文件陈说字,而 socket() 用于成立一个 socket 描述符,唯风流罗曼蒂克标志一个 socket。 那一个 socket 描述字跟文件陈诉字相通,后续的操作都有选取它,把它看成参数,通过它来拓宽局地操作。

使用closesocket()函数关闭套接口(能够先用shutdown()函数先关闭读写通道卡塔尔国

listen函数

将sockfd从未连接的套接字转换到二个被动套接字,提示内核招待受指向该套接字的接连几天哀告。

int listen(int sockfd, int backlog);

listen函数会将套接字从CLOSED状态转造成LISTEN状态,第三个参数规定基本应为对应套接字排队的最加纳Ake拉接个数。

有关backlog参数,内核为任何一个加以的监听套接字维护四个类别:

  • 1、未形成连接队列,在队列之中的套接字处于SYN_RCVD状态
  • 2、已产生队列,处于ESTABLISHED状态

七个连串之和不超过backlog的尺寸。

listen完成今后,socket就处在LISTEN状态,那时候的socket调用accept函数就足以接纳客商端发来的呼吁了。

常用的函数有:

客商端程序工作流程:

accept函数

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

用来从已做到连接队列头再次来到下三个已做到连接,假若已成功连接队列为空,那么进度就能够被打断。因而调用了accept函数之后,进度就能够被封堵,直到有新的央求到来。

第叁个参数sockfd是顾客端的套接字描述符,第一个是客商端的套接字地址构造,第八个是套接字地址布局的长短。

假使accept成功,那么重回值是由基本自动生成的全新描述符,代表所再次来到的顾客端的TCP连接。

对此accept函数,首个参数称为监听套接字描述符,重临值称为已连接套接字。服务器仅成立监听套接字,它一向存在。已连接套接字由服务器进程接收的顾客连接创制,当服务器达成有个别连接的响应后,相应的已连接套接字就被关闭了。

accept函数重返时,会回到套接字描述符或出错提示的整数,以至引用参数中的套接字地址和该地点的大小。假诺对重临值不感兴趣,能够把多少个援引参数设为空。

accept之后,贰个TCP连接就创制起来了,接着,服务器就承当客商端的伸手音讯,然后做出响应。

socket()

采纳socket()函数创制客商端套接口

recv和send函数

ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);
ssize_t send(int sockfd, const void *buff, size_t nbytes, int flags);

分别用于从客商端读取新闻和发送音讯到客商端。在这里不做过多的解说。

bind()

采取connect()函数发出也服务器建构连接的哀告(调用前能够毫不bind()端口号,由系统活动落成卡塔尔国

套接字地址构造大小和值-结果参数

能够看来,在bind函数和accept函数里面,都有贰个套接字地址构造长度的参数,区别在于一个是值方式,另二个是引用方式。套接字地址构造的传递情势决议于该组织的传递方向:是从进度到基本,依然从基本到进度。

1、从进度到底工:bind、connect、sendto。
函数将指针和指针所指内容的大小都传给了基石,于是内核知道毕竟要求从进程复制多少多少进来。

2、从底子到进度:
accept、recvfrom、getsockname、getperrname。
那多少个函数的结构大小是以只引用的艺术传送。
因为当函数被调用时,构造大小是一个值,它报告内核该协会的轻重,那样基本在写该组织时不至于越界;当函数再次来到时,构造大小又是二个结实,它告诉内核在该组织中毕竟蕴藏了某个消息。

listen()

连续几日来创设后接受send()函数发送数据,或应用recv()函数接纳数据

HTTP响应报文

出殡响应给客户端时,发送的报文要根据HTTP合同,HTTP的响应报文格式如下:

<status-line>
<headers>
<blank line>
[<response-body>]

第一行status-line,状态栏,格式:HTTP版本 状态码 状态码代表文字headers是回来报文的档期的顺序,长度等音信,接着是一个空行,然后是响应报文的实业。

二个HTTP响应报文例子:

HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 122

<html>
<head>
<title>Hello Server</title>
</head>
<body>
Hello Server
</body>
</html>

末段close函数关闭套接字,时刻保持关闭文件汇报符是二个很好的编程习于旧贯。

connect()

使用closesocet()函数关闭套接口

总结

虽说非常多东西看起来很简单,但只有投机确实入手做一遍,才意识内部的回顾,之后技能说那几个底蕴是最简易的。要更加好和更深透地精通系统的学问,你不得不另行一点一点地重新构建三次。

以此http server的贯彻源代码作者放在了我的github上,有乐趣的话能够点击查看哦。

accept()

下边介绍多少个函数的用法:

write()

socket函数:int socket(int domain,int type,int protocol)

read()

参数表达:
domain:指明左券族,也称为公约域,是四个常值。
AF_INET:IPv4 协议
AF_INET6:IPv6 协议
AF_LOCAL/AF_UNIX:Unix协议域
AF_ROUTE: 路由套接字
AF_KE:密匙套接字

close()

type:指明套接字的品种。
SOCK_STREA:字节流套接字
SOCK_DGRA:数据报套接字
SOCK_SEQPACKE:有序分组套接字
SOCK_RAW:原始套接字

Socket 的交互流程

protocol: 指明合同项目。平日为0,以选用给定的domain和type组合的系统暗许值。
IPPROTO_TCP:TCP传输公约
IPPROTO_UDP:UDP传输左券
IPPROTO_SCTP:SCTP传输左券

图片 7

函数描述:
socket 函数在功成名就时再次来到一个小的非负整数值,与公事汇报符近似,我们称它为套接字
描述符,简单称谓 sockfd。为了赢得这些套接字描述符,大家只是钦命了合同族(IPv4、IPv6
或Unix卡塔尔和套接字类型(字节流、数据报或原始套接字卡塔 尔(阿拉伯语:قطر‎。大家并未点名地点跟远程的
合同地址

图中展现了 TCP 公约的 socket 人机联作流程,描述如下:

bind函数:int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);

服务器分局址类型、socket 类型、以至和谐来创建 socket。

将四个本地公约地址付与三个套接字。对于网际网球组织议,公约地址是叁十六人的IPv4地址和128
位的IPv6地址与十三人的TCP或UDP端口号的整合。bind 函数根本用来服务器端,用来钦命地方
主机的哪位互连网接口(IP,能够是INADDENVISION_ANY,表示本地主机的任一网络接口卡塔尔国能够承担客商
端的央求,和内定端口号(即展开的守候顾客来连接的历程卡塔 尔(阿拉伯语:قطر‎。

服务器为 socket 绑定 IP 地址和端口号。

参数表达:

服务器 socket 监听端口号诉求,随即计划接到顾客端发来的连年,那个时候服务器的 socket 并未任何开辟。

sockfd: socket 函数再次来到的套接字描述符。

客户端创立 socket。

myaddr、addrlen:指向三个套接字地址布局的指针和该协会的高低。

客商端展开 socket,依据服务器 IP 地址和Port端口号试图连接服务器 socket

地方构造的常常选拔sockadr_in结构体

服务器 socket 选择到顾客端 socket 须要,被动张开,初始收受顾客端乞请,直到客商端再次来到连接新闻。此时socket 进入窒碍状态,窒碍是出于 accept() 方法会一直等到顾客端重回连接消息后才重临,然后最先一连下几个顾客端的连天央浼。

struct sockaddr_in{

客商端连接成功,向服务器发送连接情形音信。

short int sin_family; #地址族

服务器 accept() 方法重返,连接成功。

unsigned short int sin_port; #端口号

服务器和顾客端通过网络 I/O 函数实行多少的传导。

struct n_addr sin_addr; #IP地址

客户端关闭 socket。

unsigned char sin_zeor[8]; #填充0保持与struct sockaddr同样大小

服务器关闭 socket。

}

其少年老成历程中,服务器和顾客端创设连接的局地,就反映了 TCP 叁回握手的法则。

 

上面详细讲一下 socket 的各函数。

listen函数:

Socket 接口

int listen(int sockfd,int backlog)

socket 是系统提供的接口,而操作系统大超级多都以用 C/C 开采的,自然函数库也是 C/C 代码。

listen函数的率先个参数即为要监听的socket描述字,首个参数为相应socket可以排队的最洛桑接个数。socket()函数成立的socket暗中认可是一个主动类型的,listen函数将socket变为被动类型的,等待客商的连接诉求。

socket 函数

Connetc函数:

该函数会回去二个套接字描述符(socket descriptor卡塔 尔(阿拉伯语:قطر‎,不过该描述符仅是局地展开的,还无法用来读写。 如何完结张开套接字的劳作,决定于大家是顾客端依然服务器。

connect函数的首先个参数即为客商端的socket描述字,第二参数为服务器的socket地址,第八个参数为socket地址的长短。客商端通过调用connect函数来建设构造与TCP服务器的连天

函数原型

accept函数:

#includeintsocket(intdomain,inttype,intprotocol);

int accept(int sockfd,struct sockaddr *addr, socketen_t *add_len)

参数表明

参数sockfd
参数sockfd就是地点表明中的监听套接字,这些套接字用来监听二个端口,当有三个客商与服务器连接时,它选拔这几个二个端口号,而那时候这些端口号正与那几个套接字关联。当然顾客不精晓套接字那么些细节,它只晓得三个地方和二个端口号。

domain: 公约域,决定了 socket 的地址类型,在通讯中必得运用对应的地点。 常用的公约族有:AF_INET(ipv4地址与端口号的整合卡塔尔、AF_INET6(ipv6地址与端口号的结合卡塔 尔(阿拉伯语:قطر‎、AF_LOCAL(相对路线名作为地点卡塔 尔(英语:State of Qatar)。 该值的常量定义在sys/socket.h文件中。

参数addr
那是三个结果参数,它用来经受三个重临值,这重回值内定客商端的地址,当然这几个地点是透过有些地方构造来陈说的,客商应该知道这二个如何的地址构造。倘诺对顾客的位置不感兴趣,那么可以把这么些值设置为NULL。

type: 钦点 socket 类型。 常用的体系有:SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。 其中SOCK_STREAM表示提供面向连接的安宁数据传输,即 TCP 左券。 该值的常量定义在sys/socket.h文件中。

参数len
好似大家所感到的,它也是结果的参数,用来接收上述addr的构造的高低的,它指明addr构造所占领的字节个数。相通的,它也得以被装置为NULL。

protocol: 钦赐左券。 常用的商事有:IPPROTO_TCP(TCP协议)、IPPTOTO_UDP(UDP协议)、IPPROTO_SCTP(STCP公约卡塔 尔(阿拉伯语:قطر‎。 当班值日位 0 时,会自行选取type类型对应的私下认可左券。

例如accept成功再次回到,则服务器与顾客已经不错树立连接了,那个时候服务器通过accept再次来到的套接字来完毕与顾客的通讯。

bind 函数

服务器测的代码如下:对于服务带来讲,首先是自食其力socket然后绑定IP地址到socket上。然后牵头监听。

由服务端调用,把叁个地址族中的特定地点和 socket 联系起来。

当收到到央浼的时候,通过recv函数存款和储蓄在buf数组里面。並且通过send函数向对端发送新闻

函数原型

int server_function()
{
    char *sendbuf="thanks";
    char buf[256];
    int s_fd,c_fd;
    int s_len,c_len;
    struct sockaddr_in s_addr;
    struct sockaddr_in c_addr;
    s_fd=socket(AF_INET,SOCK_STREAM,0);
    s_addr.sin_family=AF_INET;
    s_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    s_addr.sin_port=PORT;
    s_len=sizeof(s_addr);
    bind(s_fd,(struct sockaddr *)&s_addr,s_len);
    listen(s_fd,10);
    while(1){
        printf("please wait a momentn");
        c_len=sizeof(c_addr);
        c_fd=accept(s_fd,(struct sockaddr *)&c_addr,(socklen_t *__restrict)&c_len);
        recv(c_fd,buf,256,0);
        buf[strlen(buf) 1]='\0';
        printf("receve message:n%sn",buf);
        send(c_fd,sendbuf,strlen(sendbuf),0);
        close(c_fd);
    }
}

#includeintbind(intsockfd,conststructsockaddr *addr, socklen_t addrlen);

 

参数表明

 

sockfd: 即 socket 描述字,由 socket() 函数创造。

顾客端的代码如下:设置好连接的IP地址和端口后,通过connect发起连接。并经过send和recv函数举行发送和吸取音信

*addr: 四个const struct sockaddr指针,指向要绑定给sockfd的商酌地址。 这么些地址构造事务所点创制socket 时的地点公约族不一样而各异,比如 ipv4 对应sockaddr_in,ipv6 对应sockaddr_in6. 那多少个构造体在应用的时候,都足以强制转变来sockaddr。 上边是那多少个结构体对应的到处的头文件:

int client_function()
{
    char *buf="come on";
    char rebuf[250];
    int sockfd,len,newsockfd,len2;
    struct sockaddr_in addr;
    sockfd=socket(AF_INET,SOCK_STREAM,0);
    addr.sin_family=AF_INET;
    addr.sin_addr.s_addr=htonl(INADDR_ANY);
    addr.sin_port=PORT;
    len=sizeof(addr);
    newsockfd=connect(sockfd,(struct sockaddr *)&addr,len);
    len2=strlen(buf);
    send(sockfd,buf,len2,0);
    sleep(5);
    recv(sockfd,rebuf,40,0);
    printf("the length of the rebuf is %d",strlen(rebuf));
    rebuf[strlen(rebuf) 1]='\0';
    printf("receive message:n%sn",rebuf);
    close(sockfd);
    return 0;
}

sockaddr:sys/socket.h

 

sockaddr_in:netinet/in.h

开垦2个极端,分别运转服务器和顾客端的代码。施行结果如下:

sockaddr_in6:netinet6/in.h

图片 8

_in 后缀意义:互联互连网(internet)的缩写,实际不是输入(input)的缩写。

 

listen 函数

服务器调用,将 socket 从叁个能动套接字转变为二个监听套接字(listening socket卡塔 尔(英语:State of Qatar), 该套接字能够接过来自客商端的延续诉求。 在暗许意况下,操作系统内核会认为 socket 函数创造的描述符对应于主动套接字(active socket卡塔 尔(英语:State of Qatar)。

函数原型

#includeintlisten(intsockfd,intbacklog);

参数表达

sockfd: 即 socket 描述字,由 socket() 函数创立。

backlog: 钦定在央求队列中的最大央浼数,进入的连接诉求将要队列中等候 accept() 它们。

connect 函数

由顾客端调用,与目标服务器的套接字创建叁个总是。

函数原型

#includeintconnect(intclientfd,conststructsockaddr *addr, socklen_t addrlen);

参数表达

clientfd: 指标服务器的 socket 描述符

*addr: 一个const struct sockaddr指针,蕴涵了指标服务器 IP 和端口。

addrlen: 合同地址的长短,如若是 ipv4 的 TCP 连接,日常为sizeof(sockaddr_in);

accept 函数

服务器调用,等待来自顾客端的接二连三央求。 当顾客端连接,accept 函数会在addr中会填充上客商端的套接字地址,並且重临叁个已接二连三描述符(connected descriptor卡塔尔国,这一个描述符能够用来利用 Unix I/O 函数与客商端通讯。

函数原型

#indclude intaccept(intlistenfd,structsockaddr *addr,int*addrlen);

参数表达

listenfd: 服务器的 socket 描述字,由 socket() 函数成立。

*addr: 一个const struct sockaddr指针,用来寄放在提议连接哀求顾客端的主机的消息

*addrlen: 合同地址的长短,假设是 ipv4 的 TCP 连接,平日为sizeof(sockaddr_in)。

close 函数

在数码传输达成之后,手动关闭连接。

函数原型

#include#includeintclose(intfd);

参数表明

fd: 必要关闭的一连 socket 描述符

网络 I/O 函数

当客商端和服务器创设连接后,能够行使网络 I/O 进行读写操作。 互连网 I/O 操作有下边几组:

read()/write()

recv()/send()

readv()/writev()

recvmsg()/sendmsg()

recvfrom()/sendto()

最常用的是 read()/write() 他们的原型是:

ssize_tread(intfd,void*buf,size_tcount);ssize_twrite(intfd,constvoid*buf,size_tcount);

由于该文是讲求于描述 socket 的办事原理,就不再详细描述那几个函数了。

落到实处一个简短 TCP 交互作用

服务端

// socket_server.cpp#include#include#include#include#include#include#include#include#defineMAXLINE 4096// 4 * 1024intmain(intargc,char**argv){intlistenfd,// 监听端口的 socket 描述符connfd;// 连接端 socket 描述符structsockaddr_in servaddr;charbuff[MAXLINE];intn;// 创造socket,并且开展错误管理if((listenfd = socket(AF_INET, SOCK_STREAM,0)) ==-1)    {printf("create socket error: %s(errno: %d)n", strerror(errno), errno);return0;    }// 初始化 sockaddr_in 数据布局memset(&servaddr,0,sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);    servaddr.sin_port = htons(6666);// 绑定 socket 和 端口if(bind(listenfd, (structsockaddr *)&servaddr,sizeof(servaddr)) ==-1)    {printf("bind socket error: %s(errno: %d)n", strerror(errno), errno);return0;    }// 监听连接if(listen(listenfd,10) ==-1)    {printf("listen socket error: %s(errno: %d)n", strerror(errno), errno);return0;    }printf("====== Waiting for client's request======n");// 持续吸收接纳顾客端的一而再央浼while(true)    {if((connfd = accept(listenfd, (structsockaddr *)NULL,NULL) ==-1))        {printf("accept socket error: %s(errno: %d)n", strerror(errno), errno);continue;        }        n = recv(connfd, buff, MAXLINE,0);        buff[n] ='\0';printf("recv msg from client: %sn", buff);        close(connfd);    }    close(listenfd);return0;}

客户端

// socket_client.cpp#include#include#include#include#include#include#include#include#include#defineMAXLINE 4096intmain(intargc,char**argv){intsockfd, n;charrecvline[4096], sendline[4096];structsockaddr_in servaddr;if(argc !=2)    {printf("usage: ./client n");return0;    }// 创建 socket 描述符if((sockfd = socket(AF_INET, SOCK_STREAM,0)) <0)    {printf("create socket error: %s(errno: %d)n", strerror(errno), errno);return0;    }// 开端化指标服务器数据构造memset(&servaddr,0,sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(6666);// 从参数中读取 IP 地址if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <=0)    {printf("inet_pton error for %sn", argv[1]);return0;    }// 连接目标服务器,并和 sockfd 联系起来。if(connect(sockfd, (structsockaddr *)&servaddr,sizeof(servaddr)) <0)    {printf("connect error: %s(errno: %d)n", strerror(errno), errno);return0;    }printf("send msg to server: n");// 从标准输入流中读撤消息fgets(sendline,4096,stdin);// 通过 sockfd,向指标服务器发送新闻if(send(sockfd, sendline,strlen(sendline),0) <0)    {printf("send msg error: %s(errno: %d)n", strerror(errno), errno);return0;    }// 数据传输结束,关闭 socket 连接close(sockfd);return0;}

Run

率先创造makefile文件

all:server client

server:socket_server.o

g -g -o socket_server socket_server.o

client:socket_client.o

g -g -o socket_client socket_client.o

socket_server.o:socket_server.cpp

g -g -c socket_server.cpp

socket_client.o:socket_client.cpp

g -g -c socket_client.cpp

clean:all

rm all

下一场使用命令:

$ make

会生成五个可施行文件:

socket_server

socket_client

独家张开四个尖峰,运营:

./socket_server

./socket_client 127.0.0.1

然后在socket_client中键入发送内容,能够再socket_server接受到一模二样的消息。

本文由星彩网app下载发布于计算机编程,转载请注明出处:Computer网络,互连网编制程序

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。