C/S模型就是server 与 client 的模型

TCP服务器模型流程图                                                               TCP 客户端模型流程图:

                

  函数使用:

(1)创建一个网络通信套接字描述符  int socket(int domain, int type, int protocol);

  参数:domain : 协议系列,常用的是 AF_INET 表示IPV4

        type : 常用的两个

        SOCK_STREAM    流式套接字 TCP 常用

        SOCK_DGRAM  数据报套接字 UDP 常用

    

    protocol:一般为0

    

  返回值:通信过程中使用的socket(一个文件描述符)

(2)把socket与 ip, 端口绑定一起     int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

  参数 :sockfd :通过socket 函数创建返回的通信文件描述符

       addr:addr 是指向 sockaddr_in 结构的指针,包含本机IP 地址和端口号协议类型等

      addrlen: addrLen : sizeof (struct sockaddr_in) 是第二个参数addr结构所占的有效长度

struct sockaddr结构 和 struct sockaddr_in结构

struct sockaddr {
  sa_family_t sa_family; //协议族
  char sa_data[]; // 14字节协议地址
} struct sockaddr_in{
  u_short sin_family;// 地址族, AF_INET,2 bytes
  u_short sin_port; // 端口,2 bytes
  struct in_addr sin_addr; // IPV4地址结构,4 bytes
  char sin_zero[]; // 8 bytes unused,作为填充
};

在bind时使用 struct sockaddr_in 结构进行初始化,然后通过 struct sockaddr 强制类型转换

sockaddr_in 与 sockaddr 结构的区别

(3) 监听绑定了ip和port的socket :int listen(int sockfd, int backlog);

  参数:sockfd:监听连接的套接字

     backlog 指定了完全成功连接的最大队列长度,它的作用在于处理可能同时出现的几个连接请求。此参数现在基本已经不用。

  返回值: 0 或 -1

完成listen()调用后,socket变成了监听

(4)阻塞等待连接 :int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

  参数: sockfd : 监听套接字

      addr : 对方地址

     addrlen:地址长度

  返回值:已建立好连接的套接字 或 -1

(5) 发送数据

  ssize_t send(int sockfd, const void *buf, size_t len, int flags);

  参数: sockfd :向哪个socket发送数据

     buf :存放数据缓存首地址

     len :发送的数据长度

     flags:发送方式(通常为0)

  返回值:成功:实际发送的字节数     失败:-1, 并设置errno

(6) 接收数据

  ssize_t recv(int sockfd, void *buf, size_t len, int flags);

  参数:socket:向哪个socket发送数据

      buf : 发送缓冲区首地址

      length : 发送的字节数

      flags : 接收方式(通常为0)

  返回值: 成功:实际接收的字节数      失败:-1, 并设置errno

(7) 客户端连接服务器的函数

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

  参数:sockfd : socket返回的文件描述符

     serv_addr : 服务器端的地址信息

     addrlen : serv_addr的长度

  返回值:0 或 -1

(8) 关闭通信socket    int close(int fd);

 编写TCP 的server和client 通信程序,服务器监听接收数据

 server.c文件:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <strings.h> #define MAX_BUF 1024
int main(int argc, const char *argv[])
{
char buf[MAX_BUF] = {};//接收数据缓存
int server_sock_fd; //服务器,socket描述符
int client_sock_fd; //链接的客户端,socket 描述符
ssize_t tybes; struct sockaddr_in server_addr;//存放服务器ip和端口
struct sockaddr_in client_addr;//存放客户端ip和端口
socklen_t len; len = sizeof(server_addr);
bzero(&server_addr,len);//清零
server_sock_fd = socket(AF_INET, SOCK_STREAM,);//创建socket,返回socket描述符
if(server_sock_fd < )
{
perror("socket fail ");
exit();
} //填充 地址和端口结构
server_addr.sin_family = AF_INET; //协议族
// server_addr.sin_port = htons(atoi(argv[2])); //服务器端口 //这两行是通过执行程序时传入参数ip和port
// server_addr.sin_addr.s_addr = inet_addr(argv[1]);//IP地址
server_addr.sin_port = htons(atoi("")); //服务器端口 , htons 把主机字节序转为网络字节序,atoi 把字符数据转为整数
server_addr.sin_addr.s_addr = inet_addr("192.168.3.132");//IP地址 ,inet_addr把字符串ip转为网络字节序整数
if(bind(server_sock_fd, (struct sockaddr*)&server_addr, len) < ) //绑定服务器 ip和port
{
perror("fail bind ");
exit();
} if( listen(server_sock_fd,) < ) //监听 服务器
{
perror("fail listen ");
exit();
} while()
{
client_sock_fd = accept(server_sock_fd,(struct sockaddr*)&client_addr,&len);//阻塞等待客户端链接
if(client_sock_fd < )
{
perror("client socket fail ");
exit();
}
printf("client ip %s port %u\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port)); //打印链接的ip 和 port
while()
{
memset(buf,,);
// tybes = recv(client_sock_fd,buf,10,0);
tybes = read(client_sock_fd,buf,);
if(tybes <= ) //断开链接或者出错
{
puts("recv error !");
break;
}
printf("recv data : %s",buf);//IO缓冲 加 换行输出
if(strstr(buf,"quit") != NULL ) //接收到 “quit” 断开连接的客户端,等待下一个连接
{
close(client_sock_fd);
break;
}
} }
close(server_sock_fd);
return ;
}

  client.c 文件;

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h> int main(int argc, const char *argv[])
{
int client_sock_fd;
char buf[] = {};
ssize_t send_tybes;
struct sockaddr_in server_addr;
socklen_t len;
len = sizeof(server_addr);
bzero(&server_addr,len); //清零 client_sock_fd = socket(AF_INET,SOCK_STREAM,); //创建客户端 socket
if(client_sock_fd < )
{
perror("client_sock_fd fail ");
exit();
} //填充服务器 地址
server_addr.sin_family = AF_INET;
// server_addr.sin_port = htons(atoi(argv[2]));
// server_addr.sin_addr.s_addr = (inet_addr(argv[1]));
server_addr.sin_port = htons(atoi(""));
server_addr.sin_addr.s_addr = (inet_addr("192.168.3.132")); if( connect(client_sock_fd, (struct sockaddr*)&server_addr, len) < ) //连接服务器
{
perror("connect fail ");
exit();
} while()
{
fgets(buf,,stdin); //终端读取数据
send_tybes = send(client_sock_fd,buf,,);
if(send_tybes <= ) //接收数据失败或者断开连接
{
printf("send fail !");
break;
}
if(strstr(buf,"quit") != NULL) //输入 “quit” 断开连接
{
break;
}
}
close(client_sock_fd);
return ;
}

测试:此时,服务器只是接收数据,不能发送数据,因为接收和终端获取数据是两个阻塞函数,需要开启多进程或者多线程处理两个阻塞问题

  

Linux 网络 tcp C/S通信模型的更多相关文章

  1. Linux下TCP网络编程与基于Windows下C#socket编程间通信

    一.linux下TCP网络编程基础,需要了解相关函数 Socket():用于套接字初始化. Bind():将 socket 与本机上的一个端口绑定,就可以在该端口监听服务请求. Listen():使s ...

  2. 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系

    [Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...

  3. Linux网络编程:基于TCP的程序开发回顾篇《转》

    面向连接的TCP程序设计 基于TCP的程序开发分为服务器端和客户端两部分,常见的核心步骤和流程: 其实按照上面这个流程调用系统API确实可以完全实现应用层程序的开发,一点问题没有.可随着时间的推移,你 ...

  4. Linux网络IO函数以及TCP连接函数包装

    标准I/O VS 网络IO 标准I/O又称为标准I/O流,从某种意义上讲是全双工的,因为程序能够在同一个流上执行输入和输出. Unix/Linux对网络的抽象是一种称为套接字的文件类型.和任何Unix ...

  5. Linux网络编程——tcp并发服务器(poll实现)

    想详细彻底地了解poll或看懂下面的代码请参考<Linux网络编程——I/O复用之poll函数> 代码: #include <string.h> #include <st ...

  6. TCP/UDP Linux网络编程详解

    本文主要记录TCP/UDP网络编程的基础知识,采用TCP/UDP实现宿主机和目标机之间的网络通信. 内容目录 1. 目标2.Linux网络编程基础2.1 嵌套字2.2 端口2.3 网络地址2.3.1 ...

  7. 基于Linux的TCP网络聊天室

    1.实验项目名称:基于Linux的TCP网络聊天室 2.实验目的:通过TCP完成多用户群聊和私聊功能. 3.实验过程: 通过socket建立用户连接并传送用户输入的信息,分别来写客户端和服务器端,利用 ...

  8. Linux网络编程一、tcp三次握手,四次挥手

    一.TCP报文格式 (图片来源网络) SYN:请求建立连接标志位 ACK:应答标志位 FIN:断开连接标志位 二.三次握手,数据传输,四次挥手 (流程图,图片来源于网络) (tcp状态转换图,图片来源 ...

  9. Linux网络驱动--snull

    snull是<Linux Device Drivers>中的一个网络驱动的例子.这里引用这个例子学习Linux网络驱动. 因为snull的源码,网上已经更新到适合最新内核,而我自己用的还是 ...

随机推荐

  1. python_ 模块 json pickle shelve

    一,什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用python编写的代码( ...

  2. UVALive 4794 Sharing Chocolate

    Sharing Chocolate Chocolate in its many forms is enjoyed by millions of people around the world ever ...

  3. React 16.4 生命周期

    补一下 React 16.4版本的生命周期图

  4. teb教程9

    通过costmap_converter来跟踪和包含动态障碍物 简介:利用costmap_converter来很容易跟踪动态障碍物 1.costmap_converter中提供了一个插件称之为costm ...

  5. 【转载】sublime text3 全攻略

    给个链接:http://www.w3cfuns.com/blog-5466732-5405668.html 等作者更新完后自己再整理

  6. Go: Println 与 Printf 的区别

    Go 学习笔记:Println 与 Printf 的区别,以及 Printf 的详细用法 2017-12-19 15:39:05 zgh0711 阅读数 26255更多 分类专栏: Go   版权声明 ...

  7. hibernate3.6异常

    WARN DTDEntityResolver:73 - recognized obsolete hibernate namespace http://hibernate.sourceforge.net ...

  8. Java——异常的基本概念

    1.异常的基本概念 1.1什么是异常 在使用计算机语言进行项目开发的过程中,即使程序员把代码写得尽善尽美,在系统的运行过程中仍然会遇到一些问题,因为很多问题不是靠代码能够避免的,比如:客户输入数据的格 ...

  9. Java——面向对象知识总结

    面向对象的三条主线: 一.类及类的成分 1.类与类的关系: java程序是关注于类的设计. 类从代码的角度:并列关系! 从执行.设计的角度:关联关系.继承关系.聚合关系 class A{ } clas ...

  10. 浅析阿里云API网关的产品架构和常见应用场景

    自上世纪60年代计算机网络发展开始,API(Application Programming Interface )随之诞生,API即应用程序接口,是实现系统间衔接的桥梁.时至今日,API市场已经形成了 ...