第三季-第24课-TCP通讯程序设计
第24课-TCP通讯程序设计
24.1 TCP编程模型函数化
这里面我们用到的框架就是上一节课的框架。即我们需要有服务器的搭建还要有客户机的搭建。执行的步骤如下:
服务器:创建socket(socket),绑定地址(bind),监听端口(listen),等待连接(accept),发/ 收数据(send/receive),结束连接(close)。
客户机:创建socket(socket),连接服务器(connet),发/收数据(send/receive),结束连接(close)。
以上一共有有8个函数,下面一一介绍:
1. 创建套接字
(1)函数名
socket()
(2)函数原型
int socket(int domain, int type, int protocol);
(3)函数功能
创建一个套接字
(4)包含的头文件
#include<sys/socket.h>
(5)返回值
成功:返回文件(套接字)描述符;
失败:-1
(6)参数说明
domain:确定通讯特性。
AF_INET(IPv4因特网域);
AF_INET6(IPv6因特网域);
AF_UNIX(UNIX域);
AF_UNSPEC(未指定)。
type:确定套接字的类型。
SOCK_DGRAM(长度固定的、无连接的不可靠报文传递);
SOCK_RAW(IP协议的数据报接口,POSIX.1中为可选);
SOCK_SEQPACKET(长度固定、有序、可靠的面向连接报文传递);
SOCK_STREAM(有序、可靠、双向的面向连接字节流)。
protocol:通常是0,表示按照参数domain和type确定通讯协议。
2. 绑定地址
(1)函数名
bind()
(2)函数原型
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
(3)函数功能
降地址绑定到一个套接字。
(4)包含的头文件
#include<sys/socket.h>
(5)返回值
成功:0;
失败:-1
(6)参数说明
sockfd:套接字的fd
addr:绑定的地址
len:绑定的地址长度
我们将结构体列出来:
struct sockaddr
{
sa_family_t sa_family;
char sa_data[14];
}
这是一个通用的地址类型(ipv4和ipv6),第一个成员表示协议族的地址类型,第二个成员表示具体的地址的值。但是我们平时用到的地址都是ipv4的,要在上述的结构上进行一定的演化:
struct sockaddr_in
{
short int sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
}
struct in_addr
{
unsigned long s_addr;
}
为了区分这两种方式的区别,我们用表格表示:
协议族 |
协议族(AF_INET) |
|
地址(14字节) |
端口号(2字节) |
|
IP地址(4字节) |
||
填充(8字节) |
注:我们生活中用到的ip地址是类似于192.168.1.1这样的,但是我们我们程序中的ip地址却是整型的,所以需要一定的转换。我们提供下面两个函数:
l in_addr_t inet_addr(const char *cp)
功能:将字符串形式的IP地址转化为整数型的IP地址(网络字节序)
范例:in_addr.saddr = inet_addr(“192.168.1.1”);
l char *inet_ntoa(struct in_addr)
功能:将整数形式的Ip地址转化为字符串形式的IP地址。
3. 设置监听端口
(1)函数名
listen()
(2)函数原型
int listen(int sockfd, int backlog);
(3)函数功能
宣告可以接受连接请求。
(4)包含的头文件
#include<sys/socket.h>
(5)返回值
成功:0;
失败:-1
(6)参数说明
sockfd:套接字的fd
backlog:提供一个提示,用于表示该进程所需要入队的连接请求数量。其实际值由系统决定。
4. 等待连接
(1)函数名
accept()
(2)函数原型
int accept(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict len);
(3)函数功能
一旦服务器调用了listen,套接字就能就收连接请求。使用函数accept获得连接请求并建立连接。没有客户机连接会是服务器发生阻塞。
(4)包含的头文件
#include<sys/socket.h>
(5)返回值
成功:文件(连接字)描述符;一个新的文件描述符,以后操作用的都是它。
失败:-1
(6)参数说明
sockfd:文件(连接字)描述符;
addr:将客户机的地址记录在这里;
len:地址的长度
5. 发送数据
(1)函数名
send()
(2)函数原型
ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);
(3)函数功能
它和write很像,但是可以指定标志来改变处理传输数据的方式。使用send时套接字必须是已经连接的。
(4)包含的头文件
#include<sys/socket.h>
(5)返回值
成功:返回发送的字节数;
失败:-1
(6)参数说明
sockfd:套接字的fd,是使用了accept建立连接后返回的fd;
buf:发送的数据存放的位置
nbytes:发送数据的长度
flags:标志,若是不用设为0;包括如下的符号:
MSG_DONTROUTE:勿将数据路由出本地网络
MSG_DONTWAIT:允许非阻塞操作(等价于O_NONBLOCK)
MSG_EOR:如果协议支持,此为记录结束
MSG_OOB:如果协议支持,发送带外数据
6. 接收数据
(1)函数名
recv()
(2)函数原型
ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
(3)函数功能
它和read很像,但是允许指定选项来控制如何接收数据。
(4)包含的头文件
#include<sys/socket.h>
(5)返回值
成功:以字节计数的消息长度,若无可用消息或对方已经按序结束则返回0;
失败:-1
(6)参数说明
sockfd:套接字的fd,是使用了accept建立连接后返回的fd;
buf:接收的数据存放的位置
nbytes:接收数据的长度
flags:标志;
7. 关闭连接
close(sockfd),和文件的关闭函数是一样的。
8. 连接服务器
(1)函数名
connect()
(2)函数原型
int connect(int sockfd, const struct sockaddr *addr, socklen_t len);
(3)函数功能
如果处理的是面向连接的网络服务(SOCK_STREAM或SOCK_SEQPACKET),在开始交换数据以前,需要在请求服务的进程套接字(客户端)和提供服务的进程套接字(服务器)之间建立一个连接。这就是connect函数的作用。
(4)包含的头文件
#include<sys/socket.h>
(5)返回值
成功:0;
失败:-1
(6)参数说明、
sockfd:客户机上创建的套接字的fd;
addr:服务器的地址;
len:地址的长度。
24.2 网络字节序
大端字节序(big-endian):不按照内存的增长方向,高位数据存储于低位内存中。
小端字节序(little-endian):按照内存的增长方向,高位数据存储于高位内存中。
在两个主机A和B之间通讯是,若是两个主机一个是大端通讯一个是小端通讯,就会使得发送的字节顺序颠倒。这就需要网络字节序的使用,它实际就是一个在通讯过程中对主机大小端的一个规定。网络字节序对应的都是大端模式的,发送端若是小端模式的我们就要先将它转化成大端模式。
但是对于接收端,我们对它的存储就要看接收方到底是什么模式的。若是大端模式,就按大端模式存储;若是小端模式,就按小端模式存储。
在linux系统中,提供了四个函数进行网络字节序的转换,如下:
1. uint32_t htonl(uint32_t hostlong);
将32位的数据从主机字节序转换为网络字
in_addr.saddr = htonl(INADDR_AN
2. uint16_t htons(uint16_t hostshort);
将16位的数据从主机字节序转换为网络字节序
3. uint32_t ntohl(uint32_t netlong);
将32位的数据从网络字节序转换为主机字节序
- 4. uint16_t ntohs(uint16_t netshort);
将16位的数据从网络字节序转换为主机字节序
24.3 实例编写
TCP通讯程序设计
tcp_server.c
#include<sys/socket.h>
#include<stdio.h>
#include<string.h> //字符串头文件
#include<netinet/in.h> //地址的头文件
#define portnum 3333
int main()
{
int sockfd;
int new_fd;
char buffer[128];//定义存储数据的字节
int nbyte;//接收到的字符串的长度
int sin_size;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
//1.创建套接字
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("creat socket error!\n");
exit(1);
}
//2.1 设置要绑定的地址
bzero(&server_addr, sizeof(struct sockaddr_in));//清零
server_addr.sin_family = AF_INET; //网络协议
server_addr.sin_port = htons(portnum); //端口,超过两个字节就要转换
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//表示任意地址,超过两个字节就要转换
//2.2 绑定地址
bind(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr));//表示指针的强制转换
//3.监听端口
listen(sockfd, 5);
while(1)
{
//4.等待连接
sin_size = sizeof(struct sockaddr);
new_fd = accept(sockfd, (struct sockaddr *)(&client_addr), &sin_size);
printf("server get connection from %s\n", inet_ntoa(client_addr.sin_addr));//取客户机的ip地址,并且将整型地址转换成字符串地址
//5.接收数据
nbyte = recv(new_fd,buffer,128,0);
buffer[nbyte] = '\0';//字符串的结束符
printf("server received: %s \n",buffer);
//6.结束连接
close(new_fd);
}
close(sockfd);
return 0;
}
tcp_client.c
#include<sys/socket.h>
#include<stdio.h>
#include<string.h> //字符串头文件
#include<netinet/in.h> //地址的头文件
#define portnum 333 //不用分号
int main()
{
int sockfd;
char buffer[128];//保存我们输入的数据
struct sockaddr_in server_addr;
//1.创建套接字
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("creat socket error!\n");
exit(1);
}
//2.1 设置要连接的服务器的地址
bzero(&server_addr, sizeof(struct sockaddr_in));//清零
server_addr.sin_family = AF_INET; //网络协议
server_addr.sin_port = htons(portnum); //端口,超过两个字节就要转换
server_addr.sin_addr.s_addr = inet_addr("192.168.153.129");
//服务其地址理论应该是通过main函数传进来的,但是这里为了方便将它写死。
//2.2 连接服务器
if(connect(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) == -1)
{
printf("connect error!\n");
exit(1);
}
//3. 发送数据到服务器
printf("please input char:\n");
fgets(buffer,128,stdin);
send(sockfd, buffer, strlen(buffer),0);
//4. 关键套接字
close(sockfd);
return 0;
}
运行:
用gcc编译好文件后,打开两个相同的终端,在一个中端里面运行./tcp_server,在另一个终端运行./tcp_client。在tcp_client终端输入的字符,在tcp_server能显示。
转载于:https://www.cnblogs.com/free-1122/p/11357245.html
第三季-第24课-TCP通讯程序设计相关推荐
- 《 Python程序设计项目案例》— 用Python开发的基于TCP通讯协议的私人聊天室 (期末大作业、结课作业、课程设计、毕业设计)
基于Python与TCP协议的私人聊天室(GUI交互界面,用户注册.用户登录.实时聊天,文件上传与下载) 用Python开发的基于TCP通讯协议的实时聊天通讯和文件共享应用 目录 基于Python与T ...
- 基于QTcpSocket和QTcpServer的Tcp通讯以及QDataStream序列化数据
为什么80%的码农都做不了架构师?>>> 最近要在QT下开发Tcp通讯,发送序列化数据以便于接收. 这里涉及到几个问题: 1.QTcpSocket.QTcpServer的通讯 ...
- TCP通讯处理粘包详解
一般所谓的TCP粘包是在一次接收数据不能完全地体现一个完整的消息数据.TCP通讯为何存在粘包呢?主要原因是TCP是以流的方式来处理数据,再加上网络上MTU的往往小于在应用处理的消息数据,所以就会引发一 ...
- 欧姆龙OMRON PLC之HostLink通讯协议(五)- CP1H以太网FINS/TCP通讯实例
//写在前面: 自2010年起,本人陆续在新浪博客上面发了几篇OMRON PLC的应用笔记,曾经很疑惑阅读量异常增加,后来发现原来是这里有人转载.现将原文照发在这里,希望能帮到做工控的同行朋友们. C ...
- 嵌入式linux学习笔记--TCP通讯整理
嵌入式linux学习笔记–TCP通讯整理 之前的项目中使用到了比较多的tcp 通讯相关的知识,一直也没有进行整理,今天准备拿出时间好好的整理一下TCP通讯的整个过程.预计会整理linux和window ...
- tcpdump和tcp通讯
tcpdump抓包分析工具 还是很好用的,针对Tcp通讯过程做一个记录,对照tcp通讯过程 介绍tcpdump man一下,介绍的很清楚在进行网络测试的时候,我们经常需要进行抓包的工作,当然有许多测试 ...
- 【转】欧姆龙OMRON PLC之 CP1H 以太网FINS/TCP通讯实例
原文:http://blog.sina.com.cn/s/blog_539cee190102wr4t.html CP1H上面的选件板插槽可以插入1-2块CP1W-CIF41模块,系统即具有了以太网功能 ...
- c++ char4个字节_西门子PLC的TCP通讯(不同项目下)①--TSEND_C指令
西门子PLC的TCP通讯(不同项目下)①--TSEND_C指令 本期说一下,不同项目下的,连个西门子1200的TCP通讯,这次我们用TSEND_C和TRCV_C组合使用,这次先了解下TSEND_C指令 ...
- java网络编程之TCP通讯
java中的网络编程之TCP协议的详细介绍,以及如何使用,同时我在下面举2例说明如何搭配IO流进行操作, 1 /* 2 *TCP 3 *建立连接,形成传输数据的通道: 4 *在连接中进行大数据量传输: ...
- boost asio 异步实现tcp通讯
一.前言 boost asio可算是一个简单易用,功能又强大可跨平台的C++通讯库,效率也表现的不错,linux环境是epoll实现的,而windows环境是iocp实现的.而tcp通讯是项目当中经常 ...
最新文章
- PyTorch核心贡献者开源书:《使用PyTorch进行深度学习》完整版现已发布!
- Swift基础--方法
- solidity modifier函数修改器 智能合约开发知识浅学(三)
- mysql中如何将默认用户名root改成其他?
- Oracle数据库的Sequence(序列)
- java 反射 proper_JAVA提高四:反射基本应用
- 升级 webpack4 变化之处
- 2020考研计算机专业课,2020考研:计算机考这4个科目,各科该这样备考
- java并发包源码分析
- 20210422-微信刷脸支付获取调用凭证authinfo的时候,提示 rawdata无效
- excel if判断单元格是否为空否求和_Excel基础函数IF的7个使用技巧,绝不是简单的判断哦!...
- Mujoco入门教程1-xml文件学习
- 设计一个RC高通滤波器或低通滤波器
- 山大计算机学院副院长屠长河,孟祥旭(山东大学教授,博士生导师)_百度百科...
- 哥尼斯堡的“七桥问题”
- muma很可能在陪你玩游戏
- 农场阳光 (simpson)
- 深入理解金融交易报文Iso8583协议
- 树莓派蓝牙连接就断开
- 写CSDN文章时,生成下标、上标、竖线的方法
热门文章
- Python爬虫基础-01-带有请求参数的爬虫
- ImageLoader的简单分析(五)
- 不显示藏宝阁试穿服务器,梦幻西游:藏宝阁试穿功能的妙用,无限回档测试
- 双亲委派模型与 Flink 的类加载策略
- 服务器云端设置怎么退出_换新手机时,3个地方要及时清除退出,别让旧手机成隐私“内鬼”...
- mysql 1236错误_MySQL主主同步环境出现1236错误
- mysql 主从 日志_mysql主从复制基于日志复制
- 修改Linux文件的读写权限
- win7动态壁纸_电脑桌面美化,高清动态壁纸
- 设置表格表头字体_Excel双栏和三栏斜线表头制作技巧