如何连接Linux上的服务器 网络编程,Linux 网络编程 一
一、网络编程基础
网络编程本身是一门很大的学问,涉及到的东西也很多,尤其是各种协议。先看图:
正如上图所示,网络编程中包含五大层面(也有区分六个层面),从应用层到物理层可以明显看出 越往下越接近计算机硬件。自己并不是专业网络编程的工程师,所以仅对这五大层面有一点点粗浅的了解,这篇文章网络编程技巧博主写的比较详细. 平时大多数所谓网络编程,其实是在传输层、网络层方面.
二、socket编程
首先,socket(套接字)编程应该属于传输层,主要实现的是端到端的通信,非常类似于很久很久以前的固话通信,应用程序可以通过它发送或者接受数据,可以对它进行像文件似得读写、关闭等操作。套接字允许应用程序将I/O插入网络中,并与网络中的其他应用程序进行通信。
其次,网络中两台或多台主机之间进行通信,必须知道对应主机的地址,也就是其IP地址,但是只知道IP地址是远远不够的,试想如你在本机A发送了一个消息,另一个台主机B也接收到到了该消息,但是到底是B主机的哪一个进程接受并处理该消息?就像你用QQ给B发送消息,但是B不可能通过陌陌收到该消息。 因此,相互通信的主机之间还必须确定一一对应的消息处理接口--端口。端口的存在,主要是为了确认消息一一对应性。另外,端口号其实就是一个从0开始的到65535之间的一个整型数字,0~1023端口,也就是常说的静态端口,已被操作系统另做它用(http,https,ftp等各种协议占用),我们自己所能使用的端口范围只能从1024开始,即动态端口取值[1024,65535].
可是看出,若要进行网络间通信,socket至少要包含IP+port两个方面,其实事实也是如此.还是以有线电话做为类比,socket其实就是自己家中的一部电话,其中IP就是家庭地址,port就是自己家的电话号码,当要给别人打电话时,别人家当然也必须有自己的座机和专属于该座机的号码.
或许我们也能猜出,socket编程是网络编程里边必不可少且及其重要的一个环节.
三、Linux+socket实践
1、目的
熟悉Linux(这里用Ubuntu16.04版本,其他版本类似)下socket编程基本流程,掌握socket编程基本原理,搞懂Linux下socket编程所必须的函数及其用法.
实验:在本地模拟两台机器,服务器和客户端,服务器监听客户端信息并能发送广播,客户端可以主动给服务器发送消息,其中消息的输入是从标准输入设备输入,并输出到标准输出--Linux 终端.
开始之前必须了解一点 什么是文件描述符,在Unix Linux系统中,文件描述符是一个非负整数,其存在作用更像一个索引,系统内核通过该"索引"找到对应的文件、设备、外设、安装的软件等等, 并通过描述符对它们进行操作。总而言之,文件描述符对应了系统上的所有文件,这里的文件并非"传统意义上的普通文件",而是指Linux系统内核所能管理1的一切,包含文档、文件、硬件设备、系统软件等等。这也体现了Linux系统的设计思想----把一切视作文件.
2、必要接口
1)、socket函数
既然socket这么重要,来看它到底是个什么东西.在Linux终端执行:man socket,出现:
通过Linux手册查询可以知道该函数所必须的头文件,函数声明和函数描述等信息.从[DESCRIPTION]字段可知,函数创建了一个用于通信的端点并返回该端点的描述符,若创建成功,返回创建套接字的文件描述符,否则返回一负数.
函数声明 int socket(int domain,int type,int protocol);
参数 domain:表示创建该socket所使用的通讯协议家族--地址族,现在一般用IPv4协议,所以通常会选择AF_INET;
参数type:指定所需的通信类型。包括数据流(SOCK_STREAM)TCP协议、数据报(SOCK-DGRAM)UDP协议和原始类型(S0CK_RAW)新网格协议的开发测试.
参数protocol:说明该套接字使用的协议族中的特定协议。如果不希望特别指定使用的协议,则置为0,使用默认的连接模式.
若要进行 基于TCP IP的网络开发测试,则函数创建方式一般为:
int listenfd = socket(AF_INET,SOCK_STREAM,0);
2)、bind函数
既然有了一部“电话”,那么就需要为该电话绑定唯一的“所属地址”,同样Linux命令行执行:man bind,同样函数声明为:
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
从手册的描述中可以看出,当成功创建socket套接字后,调用该函数可以将所创建的套接字(sockfd)和指定的地址(addr)绑定.
地址是由这样一个结构体指定:
struct sockaddr {
sa_family_t sa_family; //地址族
char sa_data[14]; //14字节的协议地址
}
上面struct sockaddr是通用地址,在网络编程中 internet sockaddr使用下面地址,两种地址可以互换:
struct sockaddr_in {
short int sin_family; /* 地址族,AF_xxx 在socket编程中只能是AF_INET */
unsigned short int sin_port; /* 端口号 (使用网络字节顺序) */
struct in_addr sin_addr; /* 存储IP地址 4字节 */
unsigned char sin_zero[8]; /* 总共8个字节,实际上没有什么用,只是为了和struct sockaddr保持一样的长度 */
};
bind()函数的第三个参数表示地址所占字节长度,socklen_t本质上是一个 unsigned int宏定义.
可以通过这样方式指定地址:
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(5188);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
//serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
首先声明网络接口地址结构,在给该地址赋值前必须将其清空.依次设置该地址的地址族、IP和端口(这里随便设置了一个),上边出现另一个新函数htons,同样终端下man htons,可知该函数的主要作用是将主机字节序转化为网络字节序,关于这两个字节序后续再深入研究.这里可以理解为:htons()的主要作用就是将十进制的ip地址和端口号转化为网络可以识别的"东东".
至此,基本可以完成座机的安装入户和号码绑定:
bing(listenfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
3)、listen监听函数
对于我们的服务器而言,它需要监听来自客户端发来的消息,Linix终端中 man listen可以看到详细信息. 函数声明为:
int listen(int socdfd,int backlog);
其中参数sockfd代指所要监听的套接字文件描述符,参数backlog表示在套接字挂起时,所能接受请求的最大队列长度.函数执行成功返回 0,否则返回 -1.
必须说明一点,当调用该函数后,参数socdfd所指定的套接字将变为被动套接字,所谓被动套接字,是指其只能用来接收来自其他用户的链接请求. 类似于改变了套接字的状态,使其只能用于接收.
4)、accept 接收函数
对于我们的服务器而言,由于其只具备接收功能,因此必须创建一个接受函数:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
函数参数不言自明,参数1sockfd表示服务器socket描述符,参数2是指客户端的协议地址,参数3为地址长度. 函数成功返回监听的等待队列中第一个套接字的描述符.
3、服务器实现
服务器的功能是监听客户端发来的消息,并将消息广播给客户端.因此需要一个循环实时监听客户端发来的消息,在本地构建一个简单的服务器如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR_EXIT(m) \
do \
{ \
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
int main(void){
int listenfd;
if(( listenfd = socket(PF_INET,SOCK_STREAM,0)) < 0){
ERR_EXIT("socket");
}
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(5188);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
//serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(bind(listenfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0)
ERR_EXIT("bind");
//一旦监听,则为被动套接字(只能接受连接,调用accep函数之前调用),这里随便给了一个最大队列长度
if(listen(listenfd,100)< 0)
ERR_EXIT("listen");
//声明一个地址,用于存储客户端链接时的协议地址
struct sockaddr_in peeraddr;
socklen_t peerlen = sizeof(peeraddr);
int conn; //返回的一个主动套接字
if((conn= accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen))<0)
ERR_EXIT("accept");
char recvbuff[1024];
while(1){
memset(recvbuff,0,sizeof(recvbuff));
int ret = read(conn,recvbuff,sizeof(recvbuff));
fputs(recvbuff,stdout);
write(conn,recvbuff,ret);
}
close(listenfd);
return 0;
}
其中用到了几个非socket API的函数:
ssize_t read(int fd,void *buf,size_t count);
ssize_t write(int fd, const void *buf, size_t count);
read()函数:负责从fd所指定文件描述符读取字节大小为count的数据到buf中.若成功返回实际读取到的字节大小,否则返回负数,返回0表示读取到文件结束.
write():将buf中的count个字节内容写入文件描述符fd.成功时返回写的字节数.
4、客户端实现
客户端的实现和服务器的实现之间大同小异,同样都需要 ” 安装电话 “ ,但是客户端的功能仅在于向外”拨打电话“. 区别在于客户端是主动发起连接请求,所以它必须知道自己所要连接的目标,之后服务器才有响应.同样客户端并不需要监听,只需要接收到服务器的广播即可. 发起连接请求需要函数 connect:
int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
在上述连接函数中,参数sockfd表示本机(客户端)的socket套接字描述符,参数addr表示服务器端的地址,参数3表示地址长度.
代码实现:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR_EXIT(m) \
do \
{ \
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
int main(void){
int sock;
if(( sock = socket(PF_INET,SOCK_STREAM,0)) < 0){
ERR_EXIT("socket");
}
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(5188);
// serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
//发起连接
connect(sock,(struct sockadddr*)&serveraddr,sizeof(serveraddr));
char recvbuf[1024]={0};
char sendbuf[1024]={0};
while(fgets(sendbuf,sizeof(sendbuf),stdin)!= NULL){
write(sock,sendbuf,strlen(sendbuf));
read(sock,recvbuf,sizeof(recvbuf));
fputs(recvbuf,stdout);
memset(recvbuf,0,sizeof(recvbuf));
}
close(sock);
return 0;
}
上述函数功能就是从客户端主动向服务器发送连接请求,并在客户端机器的标准设备上如字符,服务器接受并返回. 实现两台机器通信的模拟.
5、结果
效果如下图:
用gcc编译上述两个文件,首先启动服务器,之后启动客户端.在客户端随便输入字符,服务器解收到并广播返回. 至此基本完成目的.
三、总结
目前来看,创建服务器的一般流程是:
1.创建socket套接字(`socket`函数);
2.创建服务器地址,地址包含协议族、IP和端口号(`const struct sockaddr*`);
3.绑定套接字和服务器地址(bind函数);
4.系统监听服务器,一旦监听则该套接字变为被动套接字,只能用于接收数据(`listen`函数);
5.作为服务器,应该能接收客户端信息(`accept`函数),该函数返回一个主动套接字;
基于以上步骤,基本能搭建一个简单的服务器.
客户端的搭建相比而言简单许多:
1.创建用于连接的套接字;
2.将套接字和服务器地址连接;
3.发送消息
网络编程毕竟浪大水深,毕竟初涉,慢慢填充.
如何连接Linux上的服务器 网络编程,Linux 网络编程 一相关推荐
- 如何在 Linux 上安装服务器管理软件 Cockpit
如何在 Linux 上安装服务器管理软件 Cockpit Cockpit 是一个自由开源的服务器管理软件,它使得我们可以通过它好看的 web 前端界面轻松地管理我们的 GNU/Linux 服务器.Co ...
- 服务器不响应tcp,一直连接不上TCP服务器,服务器防火墙已经关了
大家好,现在一直连接不上TCP服务器 代码如下: // 新增8283端口,开启tcp协议 $gateway_tcp = new Gateway("tcp://0.0.0.0:8283&quo ...
- redis在容器里连接不上_Redis服务器被劫持风波,服务器相关知识共享学习
俗话说安全猛于虎,之前多多少少有所小体会:这次的上线Redis服务器被劫严重影响了开发测试和线上环境,在解决的过程也对安全方面了解了很多:总结了这次过程的排查流程以及采取的相应测试,在此与大家共享. ...
- 第五人格为什么服务器正在维修中,第五人格服务器连接不上怎么办 服务器更新后无法进入原因...
第五人格服务器连接不上怎么办 服务器更新后无法进入原因以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 第五人格服务器连接 ...
- MongoDB compass 连接不上远程服务器的解决方法
MongoDB compass 连接不上远程服务器的解决方法 参考文章: (1)MongoDB compass 连接不上远程服务器的解决方法 (2)https://www.cnblogs.com/li ...
- 阿里云ECS服务器CentOS7上安装服务器安全狗Linux版
阿里云ECS服务器CentOS7上安装服务器安全狗Linux版 ---------------- 使用root登录 1.确保服务器系统处于最新状态[root@localhost ~]# yum -y ...
- mongodb compass连接不上远程服务器(亲测 已解决)
mongo compass连接不上远程服务器的原因有很多,我也遇到过此类问题,我是因为隔了一周之后没有使用mongodb cloud 远程数据库,再次连接的时候的发现怎么连也连接不上,出现这个错误:本 ...
- 电脑连接不上wifi(不能显示可用网络)
电脑连接不上wifi(不能显示可用网络) 1.右键点击此电脑,选择"管理" 2.然后点击"设备管理器",再点击"网络适配器",看到你的网卡驱 ...
- wsus下游服务器状态,WSUS下游服务器连接不上上游服务器
WSUS下游服务器连接不上上游服务器0 only872013.08.12浏览137次分享举报 安装了一台WSUS服务器A从微软下载更新是成功的.再安一台WSUS服务器B从A哪里获得更新并作为A的副本, ...
- Linux 高并发服务器实战 - 2 Linux多进程开发
Linux 高并发服务器实战 - 2 Linux多进程开发 进程概述 概念1: 概念2: 微观而言,单CPU任意时刻只能运行一个程序 并发:两个队列交替使用一台咖啡机 并行:两个队列同时使用两台咖啡机 ...
最新文章
- 华南理工深度学习与神经网络期末考试_深度学习基础:单层神经网络之线性回归...
- My First Window构造过程,SendMessage同步,PostMessage异步
- SQLite3的数据类型转载()
- python os 文件锁_python 中给文件加锁——fcntl模块
- 用Angular制作单页应用视图切换动画
- 回顾:前端模块化和AMD、CMD规范(全)
- Kubernetes(k8s)之日志收集
- linux在命令行下打开pdf文件
- O2O优惠券使用预测
- 35岁的程序员:第18章,私欲
- 12/14 计算器雏形
- 纯前端文档预览,还要支持所有主流格式,有这一篇就足够了
- linux安装驱动报错权限没有,linux系统下安装显卡驱动程序.doc
- opencv阈值图像Threshold方法
- python证书过期_简单python脚本监控SSL证书到期提醒
- RTE2022即将开幕 声网发布RTE行业首本专业书籍《实时万象》
- laravel mysql 悲观锁_浅析乐观锁与悲观锁
- 网狐棋牌服务器IP地址配置方法
- 腐蚀rust高速箭怎么做不了_腐蚀RUST创意工坊皮肤制作教程
- SlySoft.Game.Jackal.Pro.v3.0.0.5-YAG
热门文章
- Spring AOP两种使用方式以及如何使用解析
- 产品文档如何说清楚产品业务?关注这几点就够了
- php找出函数定义位置,WordPress如何快速定位PHP函数所在文件位置及代码行号?
- 云海技术u盘怎么恢复成普通盘_BITLOCKER加密中断数据无法读取恢复一例
- android主流技术框架,android开发现在流行什么IDE和开发框架?
- python下载网页歌词_python3个人学习笔记-批量下载分析歌词2
- Ruby中带有示例的Hash.key?(value)方法
- 定期定量采购_企业常见的六种采购策略
- 交际过程的两个基本环节_跨文化交际学概论笔记(二)
- 风变的python课程怎么样_风的解释|风的意思|汉典“风”字的基本解释