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. UVA 12821 Double Shortest Paths

    Double Shortest PathsAlice and Bob are walking in an ancient maze with a lot of caves and one-way pa ...

  2. 《代码大全2》读书笔记 week 7

    博主终于继续更<代码大全2>了 (*´・ω・`)⊃,课上老师一再强调读书笔记要写出自己的心得不能简单摘抄,所以我现在基本上只会写一下自己在阅读过程中印象深刻或者有发散思考的地方,字数可能 ...

  3. RK3288 android切换耳麦通道

    通过耳机状态切换耳机mic与板子麦/work/rk3288/firefly-rk3288_android5.1_git_20180126/kernel/sound/soc/codecs/es8323. ...

  4. linux常用命令-1系统相关命令

    hostname #计算机名 passwd #修改密码 reboot #重启 shutdown –r now #立刻重启(root用户使用) shutdown –r 10 #过10分钟自动重启(roo ...

  5. 记录我个人对Telegram的了解

    对Telegram(电报) 开始的了解是以为提供了Telegram API,就可以基于它进行开发自己的即时通讯(Instant Messaging)程序. 大概使用过: webogram 和 tele ...

  6. openwrt ssh免密登录

    1 生成相关秘钥 dropbearkey -t rsa -f id_rsa dropbearkey -y -f id_rsa | grep "^ssh-rsa" >> ...

  7. Laravel5.5添加新路由文件并制定规则

    Laravel5.5里面有4个默认的路由文件,其中web.php是默认路由文件,如果需要添加其他路由文件,按照以下步骤进行. 此处以添加网站home前端路由举例,我已经先在/app/Http/Cont ...

  8. mybatis调用存储过程(@Select方式)

    存储过程还不会写的同学可以参考我另一篇文章:https://www.cnblogs.com/liuboyuan/p/9375882.html 网上已经有很多用mybatis调用的教程了,但是大部分是x ...

  9. JCF——工具类

  10. 经典排序背包——cf1203F

    先把收益为正数的处理掉:策略是挨个扫,扫n遍,碰到能买的就买,然后可以得到一个更新后的r 剩下的就看做是一个背包模型:物品(a,b)表示当背包体积>a时才能装下体积为b的该物品,问最多装几个 无 ...