tcp/ip网络编程--accept()函数返回的套接字
tcp/ip网络编程–accept()函数返回的套接字
套接字:1)套接字是对网络中不同主机的应用进程之间进行双向通信的端点的抽象;一个套接字就是网络进程通信的一端。[1]
2)套接字是用来与另一个进程跨网络通信的文件[2]
套接字表示:IP地址,端口号,传输层协议(tcp/udp)三元组构成;
其实套件字还包含各种状态跟属性等等,核心是三元组。
文件描述符:文件描述符是一个简单的非负整数,用来表示一个被进程打开的文件,每个进程都至少有三个文件描述符[2]
0——>stdin 标准输入文件
1——>stdout 标准输出文件
3——>stderr 标准错误文件
文件类型:每个Linux文件都有一个类型,表明在系统中的角色[2]。
1)普通文件
2)目录文件
3)套接字
4)其他。。。。
套接字描述符:从前面的描中,我们可以将套接字描叙符简单的理解为一种文件描述符。
tcp连接:tcp连接由一个四元组构成,它们分别是两个IP地址,两个端口号。也就是说,一个tcp连接是由一对套接字构成,[3].
socket_1{本地IP,本地端口号,TCP协议}
socket_2{外地IP,外地端口号,TCP协议}
accept(int sockfd,struct sockaddr * restrict addr,socklen_t * restrict addrlen);
//restrict 是一个关键字,在Linux中为_restrict,这个关键字只可用于指针,表明该指针是访问一个数据对象的唯一且初始的方式。
//作用:允许编译器对同类型代码进行合并并优化,提高编译效率
第一个参数sockfd是一个被socket()创建后被bind()然后listen()的处于LISTEN 状态的套接字。
第二参数addr是一个struct sockaddr 类型的指针,这个结构体会被填充外地套接字的地址,这个地址在传输层被知道。
第三个参数addlen是一个value-result参数
(value-result 参数:当函数被调用时,一个参数作为一个值从函数外传入函数内,当函数返回时,这个参数又存储了函数执行的部分结果。总是以指针/引用的方式传递)
调用者必须用addr指向的结构体的大小初始化它,函数返回时,它将包含外地地址的实际大小。
return value :
成功的话返回一个非负整数,作为已接收的套接字的文件描述符,错误则返会-1。
利用下面两个函数查询套接字信息
int getsockname(int sockfd, struct sockaddr *localaddr,socklen_t *addrlen);
//查询与套接字关联的本地地址,本地端口号
int getpeername(int sockfd, struct sockaddr *peeraddr,socklent_t *addrlen);
//查询与套接字关联的外地地址,外地端口号
下面是代码实现:
//服务器端,运行在linux虚拟机上,虚拟机的IP地址固定为192.168.79.212
#include <cstdio>
#include<cstdlib>#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
#include<iostream>#define PORT 6563
#define LISTENQ 1024using std::cout;
using std::endl;
int main() {int listen_fd, clnt_fd;//两个套接字描述符,分别关联listen套接字和连接套接字struct sockaddr_in serv_adr, clnt_adr, temp_adr;socklen_t sock_len=sizeof(serv_adr),clnt_len=sizeof(clnt_adr);listen_fd = socket(AF_INET, SOCK_STREAM, 0);memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_port = htons(PORT);//绑定端口号serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);bind(listen_fd, (sockaddr*)&serv_adr,sizeof(serv_adr));getsockname(listen_fd, (struct sockaddr*)&temp_adr, &sock_len);cout << "利用getsockname()查询绑定后的 serv_sock ip " << inet_ntoa(temp_adr.sin_addr) << ":" << ntohs(temp_adr.sin_port)<<endl;listen(listen_fd, LISTENQ);//serv_sock变为listen态getsockname(listen_fd, (struct sockaddr*)&temp_adr, &sock_len);cout << "利用getsockname()查询listen()后的 listen_sock ip " <<inet_ntoa(temp_adr.sin_addr) << ":" << ntohs(temp_adr.sin_port) << endl;clnt_fd=accept(listen_fd, (struct sockaddr*)&clnt_adr, &sock_len);getsockname(clnt_fd, (struct sockaddr*)&temp_adr, &clnt_len);cout << "利用getsockname()查询accept()返回的 clnt_sock ip " << inet_ntoa(temp_adr.sin_addr) << ":" << ntohs(temp_adr.sin_port)<<endl;getpeername(clnt_fd, (struct sockaddr*)&temp_adr, &clnt_len);cout << "利用getpeername()查询accept()返回的 clnt_sock ip " << inet_ntoa(temp_adr.sin_addr) << ":" << ntohs(temp_adr.sin_port) << endl;close(clnt_fd);close(listen_fd);return 0;}
//客户端,在Windows主机上运行 主机IP地址为192.168.79.1
#include<winsock2.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<iostream>
using std::cout;
const char* argv[] = { "hclientwin","192.168.79.212","6563" };int main()
{WSADATA wsaData;SOCKET hSocket;SOCKADDR_IN serAddr;WSAStartup(MAKEWORD(2, 2), &wsaData);hSocket = socket(PF_INET, SOCK_STREAM, 0);memset(&serAddr, 0, sizeof(serAddr));serAddr.sin_family = AF_INET;serAddr.sin_addr.s_addr = inet_addr(argv[1]);serAddr.sin_port = htons(atoi(argv[2]));connect(hSocket, (SOCKADDR*)&serAddr, sizeof(serAddr));puts("connected ...");SOCKADDR_IN serv, guest;int serv_sz, guest_sz;serv_sz = sizeof(serv);guest_sz = sizeof(guest);getsockname(hSocket, (sockaddr*)&guest, &serv_sz);cout << "connected using getsockname() get port :" <<ntohs(guest.sin_port) << std::endl;getpeername(hSocket, (sockaddr*)&serv, &serv_sz);cout << "connected using getpeername() get port :" <<ntohs(serv.sin_port) << std::endl;closesocket(hSocket);WSACleanup();return 0;
}
结果:
分析:可以看到服务器端的accept()返回的连接套接字的本地IP为虚拟机自己的IP,本地端口号为我们提前设置的端口号,外地IP为windows 主机IP号,外地端口为64131、由内核动态生成,每次运行都会有不同的结果。
可以看出在accept()函数返回后,tcp连接已经建立,具备一个四元组,一对套接字。
如果发现错误,或者由什么建议,欢迎在下面评论指出,谢谢你的观看。
如果发现错误,或者由什么建议,欢迎在下面评论指出,谢谢你的观看。
如果发现错误,或者由什么建议,欢迎在下面评论指出,谢谢你的观看。
[1]百度百科-套接字
[2]深入理解计算系统(cssap),机械工业出版社,第三版,第10章 系统级IO,622,623页。
[3]TCP/IP详解[卷1],机械工业出版社,第二版,第13章 TCP连接管理,595页。
[4]accept(2) — Linux manual page
[5]value-result参数
[6]getsockname函数和getpeername函数
tcp/ip网络编程--accept()函数返回的套接字相关推荐
- TCP/IP网络编程 学习笔记_3 --给套接字分配IP地址和端口号
IP地址和端口号 1,IP地址:为使计算机连接到网络并收发数据,必须为其分配IP地址.IP地址分为两类:IPv4(4字节地址族)和IPv6(16字节地址族).它们主要区别就是在表示IP地址所用的字节数 ...
- TCP/IP网络编程之基于TCP的服务端/客户端(二)
回声客户端问题 上一章TCP/IP网络编程之基于TCP的服务端/客户端(一)中,我们解释了回声客户端所存在的问题,那么单单是客户端的问题,服务端没有任何问题?是的,服务端没有问题,现在先让我们回顾下服 ...
- TCP/IP网络编程(1)
1. 套接字 套接字是由操作系统提供的网络数据通信软件设备,即使对网络数据传输原理不了解,也能够使用套接字完成网络数据传输.为了与远程计算机进行数据传输,需要连接到英特网,套接字就是进行网络连接的工具 ...
- 《TCP/IP网络编程》第20章
<TCP/IP网络编程>第20章 同步方法分类及CRITICAL_SECTION同步 用户模式(User mode)和内核模式(Kernal mode) 用户模式同步 内核模式同步 基于C ...
- TCP/IP网络编程之基于TCP的服务端/客户端(一)
TCP/IP网络编程之基于TCP的服务端/客户端(一) 理解TCP和UDP 根据数据传输方式的不同,基于网络协议的套接字一般分为TCP套接字和UDP套接字.因为TCP套接字是面向连接的,因此又称为基于 ...
- TCP/IP网络编程之多进程服务端(二)
TCP/IP网络编程之多进程服务端(二) 信号处理 本章接上一章TCP/IP网络编程之多进程服务端(一),在上一章中,我们介绍了进程的创建和销毁,以及如何销毁僵尸进程.前面我们讲过,waitpid是非 ...
- 网络编程+go+java,Go语言中的TCP/IP网络编程
Go语言TCP/IP网络编程 乍一看,通过TCP/IP层连接两个进程会感觉可怕, 但是在Go语言中可能比你想象的要简单的多. TCP/IP层发送数据的应用场景 当然很多情况下,不是大多数情况下,使用更 ...
- TCP/IP网络编程(一)
TCP/IP网络编程读书笔记 第1章 理解网络编程和套接字 1.1 理解网络编程和套接字 1.1.1 构建打电话套接字 1.1.2 编写 Hello World 套接字程序 1.2 基于Linux的文 ...
- TCP/IP网络编程:P1->理解网络编程和套接字
本系列文章为<TCP/IP网络编程----尹圣雨>学习笔记 文章目录 一.理解网络编程和套接字 1.1 构建接电话套接字 1.2 编写"Hello world!"服务器 ...
最新文章
- OneAPM挂牌新三板,资本市场一片看好!
- JavaScript时间日期格式转化
- MySQL创建触发器(CREATE TRIGGER)
- flutter 日历_Flutter:一个更贴近真实项目的练习
- Docker shipyard 试用
- 休眠身份,序列和表(序列)生成器
- System.Runtime.InteropServices浅见
- python按某列拆分excel表格_python带格式拆分excel表单,copy库完美搞定
- html站内消息列表,WebSocket实现站内消息实时推送
- 问题3:点击应用icon,会卡几秒后才进入到启动界面
- java的连接 初始化_java类从加载、连接到初始化过程详解
- 使用 SoundSource 取代Mac系统内置的音量控制器
- 中国省份、市区、地区县信息表
- python程序设计基础课后习题答案(电子版,可复制)
- 计算机控制面板设置密码,如何设置修改电脑的开机密码
- 熊啸锋:在线生成个人网站,如何建立个人网站教程
- langconv 安装 | python繁体 简体转换
- mysql时间格式化到小时_mysql 时间格式化
- 易恢复15版EasyRecovery电脑数据恢复软件
- echarts 横坐标显示一个月_图表太丑怎么破,ECharts神器带你飞!