0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

TCP实现服务器与客户端的通信流程

C语言编程基础 来源:未知 作者:胡薇 2018-05-04 17:52 次阅读

主要函数:

TCP实现服务器与客户端的通信流程

//服务器端---服务器是一个被动的角色

1.socket //买一个手机

2.bind //SIM卡 绑定一个手机号(ip+port)

3.listen //待机(等待电话打入)

4.accept //接听电话

5.read/write //通话

6.close //挂机

//客户端---客户端是一个主动发起请求的一端

1.socket //买一个手机

2.bind(可选的) //SIM卡(绑定号码)

3.connect //拨打电话

4.read/write //通话

5.close //挂机

//1.socket ---- 插口

int socket(int domain, int type, int protocol);

功能: 创建通信的一端 (socket)

参数:

@domain //"域" --范围

AF_INET //IPV4 协议的通信

@type SOCK_STREAM //TCP (流式套接字)

@protocol 0 //LINUX下 流式套接字 ==>TCP

//协议

返回值:

成功 对应的socket文件描述符

失败 返回-1

注意:

文件描述符:

实际上就是 创建好的 socket的一个标识符

//2.bind

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

功能:

给指定的 socket 绑定地址信息

参数:

@sockfd //表示操作的socket

@addr //填充的地址信息(ip + port)

@addrlen //地址信息结构体的大小

返回值:

成功 0

失败 -1

//通用的地址结构

struct sockaddr {

sa_family_t sa_family; //AF_INET //IPV4的协议

char sa_data[14];//(ip+port)

}

//网络通信的地址结构(internet)

struct sockaddr_in {

sa_family_t sin_family; /* address family: AF_INET */

in_port_t sin_port; /* port in network byte order */

struct in_addr sin_addr; /* internet address */

};

/* Internet address. */

struct in_addr {

uint32_t s_addr; /* address in network byte order */

};

//1.定义一个 地址结构体变量

struct sockaddr_in addr;

bzero(&addr,sizeof(addr)); //清0的函数

//2.之后进行信息填充

addr.sin_family = AF_INET;

addr.sin_port = htons(8888);

addr.sin_addr.s_addr = inet_addr("127.0.0.1");

//127.0.0.1 是回环测试的地址

//3.进行绑定

if(bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)) < 0)

{

perror("bind fail");

return 0;

}

//3.listen --- 设置监听 ---作用:让操作系统监控是否有客户端发起连接

int listen(int sockfd, int backlog);

功能:

设置监听

参数:

@sockfd //监听套接字

@backlog //监听队列的大小

返回值

成功 0

失败 -1

listenfd

--------------监听队列------------------

fd1 fd2 fd3 fd4

|

-|--------------------------------------

|

\---->建立好连接的套接字

accept函数获取已连接的套接字 返回对应

的标识符

|--->后面的读写操作 都是通过这个标识符

进行的

-----------------------------------------------

accept(); //accept 从监听队列中获得已连接的的socket,返回一个标示符来表示已连接的socket

//后续通过已连接的socket进行通信

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

功能: 获取连接

参数:

@sockfd //监听套接字的fd(标识符)

@addr //来电显示(保存对端的地址信息)(ip+port)

@addrlen //表示 addr 参数对应类型的大小,值结果参数 --- 就是在用的时候,必须先赋一个初值,最后函数调用完成

//通过该参数,返回一个结果值

返回值:

成功 已连接的socket的标识符

失败 -1

//connect ---发起连接

int connect(

int sockfd, //表示 进行通信的 socket的标识符

const struct sockaddr *addr, //对端的地址信息(ip+port)

socklen_t addrlen); //表示的是 addr 参数类型的长度

参数:

@sockfd //通过socket函数获得的fd

@addr //服务器端的地址

@addrlen //参数addr类型的大小

//数据流向 fd --> buf (count 表示一次读取多少个字节)

ssize_t read(int fd, void *buf, size_t count);

//数据流向 buf--> fd (count 表示一次写多少个字节)

ssize_t write(int fd, const void *buf, size_t count);

参数:

@fd 就是要操作的 socket对应的 标示符

@buf 保存数据的一块内存首地址

@count 一次操作的字节数

confd

char buf[] = "hello QCXY\n";

write(confd,buf,strlen(buf)); //写 数据到socket中

//读数据出来

char rbuf[1024] = {0}; //表示申请了一块1024个字节大小

//的内存空间

read(confd,rbuf,sizeof(rbuf)); //读取数据

//练习:

实现 客户端 向服务器发送数据

服务器回发数据的功能

client ----- server

scanf(); ---(1)----> read 之后printf

read <--(2)----         write

printf

循环做,结束条件

当客户端输入 "quit"字符串时 客户端结束

怎么判断客户端读到的是"quit"

c语言

"quit" == buf; (X) //不能这么写

//字符串的比较函数

strcmp("quit",buf);

strncmp("quit",buf,4);

客户端的程序:

#include

#include /* See NOTES */

#include

#include

#include

#include

#include

//./client 127.0.0.1 8888

int main(int argc, const char *argv[])

{

int fd;

int ret = 0;

char buf[1024] = {0};

char rbuf[1024] = {0};

//处理命令行参数

//1.socket(手机)

//2.bind(电话卡)

//3.connect (拨打电话)

//处理命令行参数

if(argc != 3)

{

printf("Usage: %s\n",argv[0]);

return -1;

}

//1.socket(手机)

fd = socket(AF_INET,SOCK_STREAM,0);

if(fd < 0) //出错处理

{

perror("socket fail");

return -1;

}

printf("fd = %d\n",fd);

//2.bind(电话卡)---绑定的是客户端自己的地址信息

//客户端地址信息

//1.定义一个 地址结构体变量

struct sockaddr_in cli_addr;

bzero(&cli_addr,sizeof(cli_addr)); //清0的函数

//2.之后进行信息填充

cli_addr.sin_family = AF_INET;

cli_addr.sin_port = htons(7777);

cli_addr.sin_addr.s_addr = inet_addr(argv[1]);

if(bind(fd,(struct sockaddr*)&cli_addr,sizeof(cli_addr)) < 0)

{

perror("bind fail");

return -1;

}

//服务器端的地址信息

//1.定义一个 地址结构体变量

struct sockaddr_in addr;

bzero(&addr,sizeof(addr)); //清0的函数

//2.之后进行信息填充

addr.sin_family = AF_INET;

addr.sin_port = htons(atoi(argv[2]));

addr.sin_addr.s_addr = inet_addr(argv[1]);

//3.connect (拨打电话)

if(connect(fd,(struct sockaddr*)&addr,sizeof(addr))<0)

{

perror("connect fail");

return -1;

}

printf("connect success\n");

//通信过程

while(1)

{

//客户端从键盘获得数据

//数据流向stdin --> buf

fgets(buf,sizeof(buf),stdin); //stdin表示是从键盘获得数据

//发送给服务器

write(fd,buf,strlen(buf));

//接受服务器回发的消息

ret = read(fd,rbuf,sizeof(rbuf));

//如果回发的消息是

//quit

//则结束

rbuf[ret] = '\0';

printf("rbuf = %s\n",rbuf);

if(strncmp("quit",buf,4) == 0)

{

close(fd);

break;

}

}

return 0;

}

服务端

#include

#include /* See NOTES */

#include

#include

#include

#include

//./server 127.0.0.1 8888

int main(int argc, const char *argv[])

{

int fd = 0;

int connfd = 0;

int ret = 0;

char buf[1024] = {0};

//处理命令行参数

if(argc != 3)

{

printf("Usage: %s\n",argv[0]);

return -1;

}

//1.socket 创建套接字

fd = socket(AF_INET,SOCK_STREAM,0);

if(fd < 0) //出错处理

{

perror("socket fail");

return -1;

}

printf("fd = %d\n",fd);

//2.绑定

//1.准备地址信息

//2.绑定

//

//1.定义一个 地址结构体变量

struct sockaddr_in addr;

bzero(&addr,sizeof(addr)); //清0的函数

//2.之后进行信息填充

addr.sin_family = AF_INET;

addr.sin_port = htons(atoi(argv[2]));

addr.sin_addr.s_addr = inet_addr(argv[1]);

//127.0.0.1 是回环测试的地址

//3.进行绑定

if(bind(fd,(struct sockaddr*)&addr,sizeof(addr)) < 0)

{

perror("bind fail");

return 0;

}

printf("bind success\n");

//4.设置监听

if(listen(fd,5) < 0)

{

perror("listen fail");

return -1;

}

struct sockaddr_in peer_addr;

socklen_t addrlen = sizeof(peer_addr);

//5.获取连接 -- 接听电话

while(1) //可以不断接受客户端的请求

{

//connfd = accept(fd,NULL,NULL);

connfd = accept(fd,(struct sockaddr*)&peer_addr,&addrlen);

if(connfd < 0)

{

perror("accept fail");

return -1;

}

printf("connfd = %d\n",connfd);

printf("-----------------------\n");

printf("ip = %s\n",inet_ntoa(peer_addr.sin_addr));

printf("port = %d\n",ntohs(peer_addr.sin_port));

printf("-----------------------\n");

//通信过程

//效果实现数据回发

while(1)

{

//read 与 write 的返回值 大于0 时表示的是

//一次成功操作到的字节数

ret = read(connfd,buf,sizeof(buf));

//hello

buf[ret] = '\0'; //添加'\0'--转换成字符串

printf("buf = %s\n",buf);//字符串打印 需要

//结束标志 '\0'

if(ret == 0 || strncmp(buf,"quit",4) == 0)

{

close(connfd);

break;

}

write(connfd,buf,ret);

}

} //telnet

return 0;

}

补充:

可以用如下函数替代read,write

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);

@sockfd //进行操作的socket的文件描述符

@buf //保存数据的首地址

@len //一次操作的字节数

@flags //标志0--默认的操作方式(阻塞)

返回值:

成功 成功操作的字节数

失败 -1&errno

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 通信
    +关注

    关注

    18

    文章

    5970

    浏览量

    135851
  • TCP
    TCP
    +关注

    关注

    8

    文章

    1349

    浏览量

    78986

原文标题:C语言中如何实现网络通信(流程实例)

文章出处:【微信号:xx-cyy,微信公众号:C语言编程基础】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    用labview做个服务器,和若干个客户端同时进行TCP通信

    用labview做个服务器,和若干个客户端同时进行TCP通信,有哪位高手做过的指点下小弟吧,不胜感激!
    发表于 05-21 19:01

    labview TCP客户端

    最近在做一个labview 客户端测试小程序,服务器采用MFC编写,客户端采用TCP侦听函数,通信可以连接,数据也正确,但是
    发表于 06-30 23:15

    【NanoPi NEO试用体验】TCP通信客户端程序

    不适合传输实时视频这种数据量比较大的。通信双方是基于C/S架构,这里使用电脑TCP助手作为服务器,NEO写了客户端的程序。双方大致
    发表于 12-28 23:40

    labview-TCP客户端服务器

    labview-TCP客户端服务器一个服务器上位机,多个下位机客户端
    发表于 03-26 16:58

    如何使用Socket实现UDP客户端

    本教程介绍了如何利用socket 编程来实现一个 UDP 客户端,与服务器进行通信。与开发 TCP 客户
    发表于 03-30 07:39

    Labview TCP服务器和多个客户端问题

    我开启一个Labview TCP服务器,与外部两个TCP客户端连接,两个客户端会定时给服务端发送
    发表于 04-13 18:43

    当WiFi信号变低时,服务器客户端之间的TCP通信丢失,如何使客户端重新连接?

    大家好, 当 WiFi 信号变低时,服务器客户端之间的 TCP 通信丢失,比如超过 -80dBm。一旦客户端断开连接,它就无法重新连接并正
    发表于 05-15 07:31

    服务器客户端之间的TCP通信丢失怎么处理?

    嗨, 当 WiFi 信号变低时,比如超过 -80dBm,我面临服务器客户端之间的 TCP 通信丢失。一旦客户端断开连接,它就无法重新连接并
    发表于 05-16 08:19

    TCP实现服务器客户端通信流程实例

    //服务器端---服务器是一个被动的角色 1.socket //买一个手机 2.bind //SIM卡 绑定一个手机号(ip+port) 3.listen //待机(等待电话打入)
    的头像 发表于 04-06 11:49 1.2w次阅读

    网络调试和串口调试集合UDP TCP客户端TCP服务器端应用程序免费下载

    本文档的主要内容详细介绍的是网络调试和串口调试集合UDP TCP客户端TCP服务器端应用程序免费下载。
    发表于 08-30 08:00 16次下载
    网络调试和串口调试集合UDP <b class='flag-5'>TCP</b><b class='flag-5'>客户端</b>和<b class='flag-5'>TCP</b><b class='flag-5'>服务器端</b>应用程序免费下载

    Linux下网络编程TCP并发服务器TCP客户端程序免费下载

    本文档的主要内容详细介绍的是Linux下网络编程TCP并发服务器TCP客户端程序免费下载
    发表于 01-08 15:12 9次下载
    Linux下网络编程<b class='flag-5'>TCP</b>并发<b class='flag-5'>服务器</b>和<b class='flag-5'>TCP</b><b class='flag-5'>客户端</b>程序免费下载

    STM32+LWIP服务器实现客户端连接

    (UCOSIII版本) 的基础上进行修改,实现客户端连接的一个方法。1、TCP服务器创建过程建立一个TCP
    发表于 12-23 19:59 61次下载
    STM32+LWIP<b class='flag-5'>服务器</b><b class='flag-5'>实现</b>多<b class='flag-5'>客户端</b>连接

    Linux下TCP网络编程-创建服务器客户端

    这篇文章介绍在Linux下的socket编程,完成TCP服务器客户端的创建,实现数据通信
    的头像 发表于 08-14 09:26 2419次阅读
    Linux下<b class='flag-5'>TCP</b>网络编程-创建<b class='flag-5'>服务器</b>与<b class='flag-5'>客户端</b>

    基于LwIP的TCP客户端设计

    上一篇我们基于LwIP协议栈的RAW API实现了一个TCP服务器的简单应用,接下来一节我们来实现一个TCP
    的头像 发表于 12-14 15:12 2239次阅读
    基于LwIP的<b class='flag-5'>TCP</b><b class='flag-5'>客户端</b>设计

    服务器Server和客户端Client的区别

    例如在使用TCP通讯建立连接时采用客户端服务器模式,这种模式又常常被称为主从式架构,简称为C/S结构,属于一种网络通讯架构,将通讯的双方以客户端(Client )与
    的头像 发表于 09-06 16:13 1328次阅读
    <b class='flag-5'>服务器</b>Server和<b class='flag-5'>客户端</b>Client的区别