本文属于转载,稍有改动,以利于学习。

(一)Linux网络编程--网络知识介绍

Linux网络编程--网络知识介绍
客户端和服务端 
        网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端.

客户端
        在网络程序中,如果一个程序主动和外面的程序通信,那么我们把这个程序称为客户端程序。 比如我们使用ftp程序从另外一
        个地方获取文件的时候,是我们的ftp程序主动同外面进行通信(获取文件), 所以这个地方我们的ftp程序就是客户端程序。 
服务端
        和客户端相对应的程序即为服务端程序。被动的等待外面的程序来和自己通讯的程序称为服务端程序。 
        比如上面的文件获取中,另外一个地方的程序就是服务端,我们从服务端获取文件过来。 
互为客户和服务端
        实际生活中有些程序是互为服务和客户端。在这种情况项目, 一个程序既为客户端也是服务端。

常用的命令 
        由于网络程序是有两个部分组成,所以在调试的时候比较麻烦,为此我们有必要知道一些常用的网络命令
netstat 
        命令netstat是用来显示网络的连接,路由表和接口统计等网络的信息.netstat有许多的选项. 
        我们常用的选项是-na 用来显示详细的网络状态.至于其它的选项我们可以使用帮助手册获得详细的情况. 
telnet 
        telnet是一个用来登录远程的程序,但是我们完全可以用这个程序来调试我们的服务端程序的. 
        比如我们的服务器程序在监听8888端口,我们可以用
                telnet localhost 8888
        来查看服务端的状况. 
pingping 程序用来判断网络的状态是否正常,最经常的一个用法是
        ping 192.168.0.1
        表示我们想查看到192.168.0.1的硬件连接是否正常 
TCP/UDP介绍 
        TCP(Transfer Control Protocol)传输控制协议是一种面向连接的协议, 当我们的网络程序使用这个协议的时候,
        网络可以保证我们的客户端和服务端的连接是可靠的,安全的.

UDP(User Datagram Protocol)用户数据报协议是一种非面向连接的协议, 
        这种协议并不能保证我们的网络程序的连接是可靠的,所以我们现在编写的程序一般是采用TCP协议的.

(二)Linux网络编程--初等网络函数介绍(TCP)

Linux系统是通过提供套接字(socket)来进行网络编程的.网络程序通过socket和其它几个函数的调用,
   会返回一个 通讯的文件描述符,我们可以将这个描述符看成普通的文件的描述符来操作,这就是linux的设备无关性的好处.
   我们可以通过向描述符读写操作实现网络之间的数据交流. 
(一)socket 
  
  int socket(int domain, int type,int protocol)

domain:说明我们网络程序所在的主机采用的通讯协族(AF_UNIX和AF_INET等). 
        AF_UNIX只能够用于单一的Unix 系统进程间通信,
        而AF_INET是针对Internet的,因而可以允许在远程 
        主机之间通信(当我们 man socket时发现 domain可选项是 PF_*而不是AF_*,因为glibc是posix的实现所以用PF代替了AF,
        不过我们都可以使用的).

type:我们网络程序所采用的通讯协议(SOCK_STREAM,SOCK_DGRAM等) 
        SOCK_STREAM表明我们用的是TCP 协议,这样会提供按顺序的,可靠,双向,面向连接的比特流. 
        SOCK_DGRAM 表明我们用的是UDP协议,这样只会提供定长的,不可靠,无连接的通信.

protocol:由于我们指定了type,所以这个地方我们一般只要用0来代替就可以了 socket为网络通讯做基本的准备.
  成功时返回文件描述符,失败时返回-1,看errno可知道出错的详细情况.

(二)bind 
  int bind(int sockfd, struct sockaddr *my_addr, int addrlen)

sockfd:是由socket调用返回的文件描述符.

addrlen:是sockaddr结构的长度.

my_addr:是一个指向sockaddr的指针. 在中有 sockaddr的定义

struct sockaddr{
                unisgned short  as_family;
                char            sa_data[14];
        };

不过由于系统的兼容性,我们一般不用这个头文件,而使用另外一个结构(struct sockaddr_in) 来代替.在中有sockaddr_in的定义 
        struct sockaddr_in{
                unsigned short          sin_family;     
                unsigned short int      sin_port;
                struct in_addr          sin_addr;
                unsigned char           sin_zero[8];
        }
  我们主要使用Internet所以
        sin_family一般为AF_INET,
        sin_addr设置为INADDR_ANY表示可以和任何的主机通信,
        sin_port是我们要监听的端口号.sin_zero[8]是用来填充的. 
  bind将本地的端口同socket返回的文件描述符捆绑在一起.成功是返回0,失败的情况和socket一样

(三)listen 
  int listen(int sockfd,int backlog)

sockfd:是bind后的文件描述符.

backlog:设置请求排队的最大长度.当有多个客户端程序和服务端相连时, 使用这个表示可以介绍的排队长度. 
  listen函数将bind的文件描述符变为监听套接字.返回的情况和bind一样.

(四)accept 
  int accept(int sockfd, struct sockaddr *addr,int *addrlen)

sockfd:是listen后的文件描述符.

addr,addrlen是用来给客户端的程序填写的,服务器端只要传递指针就可以了. bind,listen和accept是服务器端用的函数,
  accept调用时,服务器端的程序会一直阻塞到有一个 客户程序发出了连接. accept成功时返回最后的服务器端的文件描述符,
  这个时候服务器端可以向该描述符写信息了. 失败时返回-1

(五)connect 
   int connect(int sockfd, struct sockaddr * serv_addr,int addrlen)

sockfd:socket返回的文件描述符.

serv_addr:储存了服务器端的连接信息.其中sin_add是服务端的地址

addrlen:serv_addr的长度

connect函数是客户端用来同服务端连接的.成功时返回0,sockfd是同服务端通讯的文件描述符 失败时返回-1.

(六)实例

/******* 服务器程序  (server.cpp) ************/

 #include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
using namespace std;
int main(int argc, char *argv[])
{
int sockfd,new_fd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size,portnumber;
char hello[] = "Hello!Fine?\n";
if(argc != ){
fprintf(stderr,"Usage:%s portnumber\a\n",argv[]);
exit();//force quit
}
if((portnumber=atoi(argv[])) < )
{
fprintf(stderr,"Usage:%s portnumber\a\n",argv[]);
exit();
}
/* 服务器端开始建立socket描述符 */
if((sockfd = socket(AF_INET,SOCK_STREAM,)) == -)
{
fprintf(stderr,"Socket error:%s\n\a",strerror(errno));
exit();
}
/* 服务器端填充 sockaddr结构 */
bzero(&server_addr,sizeof(struct sockaddr_in));//#include <string.h>功能:置字节字符串s的前n个字节为零。
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(portnumber);
/*
*
* htonl()--"Host to Network Long"
ntohl()--"Network to Host Long"
htons()--"Host to Network Short"
ntohs()--"Network to Host Short"
*
*/
//捆绑sockfd描述符
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr)) == -)
{
fprintf(stderr,"Bind err:%s\n\a",strerror(errno));
exit();
}
/* 监听sockfd描述符*/
if(listen(sockfd,) == -)
{
fprintf(stderr,"Listen error:%s\n\a",strerror(errno));
exit();
}
while () {
//the server blocks until the client app builds connection.
sin_size = sizeof(struct sockaddr_in);
if((new_fd = accept(sockfd,(struct sockaddr *)(&client_addr),(socklen_t*)&sin_size)) == -)
{
fprintf(stderr,"Accept error:%s\n\a",strerror(errno));
exit();
}
fprintf(stderr,"Server get connection from %s\n",inet_ntoa(client_addr.sin_addr));
//<arpa/inet.h> 网络字节序IP转化点分十进制IP
if(write(new_fd,hello,strlen(hello)) == -)
{
fprintf(stderr,"Write Error:%s\n",strerror(errno));
exit();
}
close(new_fd);
}
close(sockfd);
exit();
}

//客户端 client.cpp
 #include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h> using namespace std; int main(int argc,char *argv[])
{
int sockfd;
char buffer[];
struct sockaddr_in server_addr;
struct hostent *host;
int portnumber,nbytes; if(argc!=)
{
fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[]);
exit();
} if((host=gethostbyname(argv[]))==NULL)
{
fprintf(stderr,"Gethostname error\n");
exit();
} if((portnumber=atoi(argv[]))<)
{
fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[]);
exit();
} //客户程序建立sockfd
if((sockfd=socket(AF_INET,SOCK_STREAM,))==-)
{
fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
exit();
} /* 客户程序填充服务端的资料 */
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(portnumber);
server_addr.sin_addr=*((struct in_addr *)host->h_addr); /* 客户程序发起连接请求 */
if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-)
{
fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));
exit();
} /* 连接成功了 */
if((nbytes=read(sockfd,buffer,))==-)
{
fprintf(stderr,"Read Error:%s\n",strerror(errno));
exit();
}
buffer[nbytes]='\0';
printf("I have received:%s\n",buffer);
/* 结束通讯 */
close(sockfd);
exit();
}

gcc编译这两个文件后,生成server和client,当然,为了省事儿,可以用codeblocks直接运行,可以看到目录下新生成server和client。运行 ./server 8080& (其中8080为端口号,可以自行更换),再运行 ./client localhost 8080即可。

(七) 总结 
总的来说网络程序是由两个部分组成的--客户端和服务器端.它们的建立步骤一般是:

服务器端
socket-->bind-->listen-->accept

客户端
socket-->connect

(八) 附录

   sockaddr结构体
sockaddr的缺陷:sa_data把目标地址和端口信息混在一起了
struct sockaddr {
unsigned short sa_family;
   char sa_data[];
   };
sa_family是通信类型,最常用的值是 "AF_INET"
sa_data14字节,包含套接字中的目标地址和端口信息 sockaddr_in 结构体
sockaddr_in结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中
struct sockaddr_in {
   short int sin_family;
   unsigned short int sin_port;
struct in_addr sin_addr;
struct in_addr {
unsigned long s_addr;
} unsigned char sin_zero[];
} sin_port和sin_addr都必须是NBO
一般可视化的数字都是HBO(本机字节顺序) sin_zero 初始值应该使用函数 bzero() 来全部置零。
一般采用下面语句
struct sockaddr_in cliaddr;
bzero(&cliaddr,sizeof(cliaddr)); sockaddr_in结构体变量的基本配置
struct sockaddr_in ina; bzero(&ina,sizeof(ina)); ina.sin_family=AF_INET; ina.sin_port=htons();
ina.sin_addr.s_addr = inet_addr("132.241.5.10"); sockaddr 和 sockaddr_in的相互关系
一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数
sockaddr_in用于socket定义和赋值
sockaddr用于函数参数 最典型的源、目的节点socket定义
对于源、目的地址和源、目的地址端口,需要建立两个socket变量
cliaddr绑定源地址和源端口
servaddr用于connect和sendto的设定目的地址和目的端口
struct sockaddr_in servaddr,cliaddr; create_socket(char *server_addr_string,unsigned int server_port)
{
源socket赋值
bzero(&cliaddr,sizeof(cliaddr));
cliaddr.sin_family = AF_INET;
通常TCP/UDP 协议源地址和端口都是随机的
cliaddr.sin_addr.s_addr = htons(INADDR_ANY);
cliaddr.sin_port = htons(); 目的socket赋值
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_aton(server_addr_string,&servaddr.sin_addr);
servaddr.sin_port = htons(server_port);
} 网络字节顺序 (Network Byte Order) NBO
结构体的sin_port和sin_addr都必须是NBO 本机字节顺序 (Host Byte Order) HBO
一般可视化的数字都是HBO NBO,HBO二者转换
inet_addr() 将字符串点数格式地址转化成无符号长整型(unsigned long s_addr s_addr;)
inet_aton() 将字符串点数格式地址转化成NBO
inet_ntoa () 将NBO地址转化成字符串点数格式
htons() "Host to Network Short"
htonl() "Host to Network Long"
ntohs() "Network to Host Short"
ntohl() "Network to Host Long"
常用的是htons(),inet_addr()正好对应结构体的端口类型和地址类型 三种给socket赋值地址的方法
inet_aton(server_addr_string,&myaddr.sin_addr);
myaddr.sin_addr.s_addr = inet_addr("132.241.5.10");
INADDR_ANY转不转NBO随便
myaddr.sin_addr.s_addr = htons(INADDR_ANY);
myaddr.sin_addr.s_addr = INADDR_ANY; 两种给socket 赋值端口的方法
#define MYPORT 3490
myaddr.sin_port = htons(MYPORT);
(随机端口)转不转NBO随便
myaddr.sin_port = htons();
myaddr.sin_port = ; htons/l和ntohs/l等数字转换都不能用于地址转换,因为地址都是点数格式,所以地址只能采用数字/字符串转换如inet_aton,inet_ntoa;
唯一可以用于地址转换的htons是针对INADDR_ANY
cliaddr.sin_addr.s_addr = htons(INADDR_ANY) inet_addr()与inet_aton()的区别
inet_addr() 是返回值型
struct sockaddr_in ina; ina.sin_addr.s_addr = inet_addr("132.241.5.10");
inet_aton() 是参数指针型
struct sockaddr_in ina; inet_aton("132.241.5.10",&ina.sin_addr); inet_ntoa 将NBO地址转化成字符串点数格式
参数:结构体变量.sinaddr
返回值:字符串指针
a1 = inet_ntoa(ina.sin_addr);
printf("address 1: %s\n",a1);
address : 132.241.5.10 inet_addr()的缺陷:必须对-1做检测处理
因为inet_addr()的结果是整型,而发生错误时返回-。
而 ina.sin_addr.s_addr是unsigned long型
-1在long short显示成111111111,和IP地址255.255.255.255相符合!会被误认为广播地址!

网络地址in_addr等结构体

linux网络编程_1的更多相关文章

  1. 【深入浅出Linux网络编程】 "开篇 -- 知其然,知其所以然"

    [深入浅出Linux网络编程]是一个连载博客,内容源于本人的工作经验,旨在给读者提供靠谱高效的学习途径,不必在零散的互联网资源中浪费精力,快速的掌握Linux网络编程. 连载包含4篇,会陆续编写发出, ...

  2. 【linux草鞋应用编程系列】_5_ Linux网络编程

    一.网络通信简介   第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章.   二.linux网络通信     在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...

  3. Linux 网络编程(IO模型)

    针对linux 操作系统的5类IO模型,阻塞式.非阻塞式.多路复用.信号驱动和异步IO进行整理,参考<linux网络编程>及相关网络资料. 阻塞模式 在socket编程(如下图)中调用如下 ...

  4. linux网络编程 no route to host 解决方案

    linux网络编程 no route to host 解决方案 [整合资料] (2013-05-13 21:38:12) 转载▼ 标签: net iptables it 分类: Linux 参考资料h ...

  5. linux网络编程-(socket套接字编程UDP传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  6. Linux网络编程&内核学习

    c语言: 基础篇 1.<写给大家看的C语言书(第2版)> 原书名: Absolute Beginner's Guide to C (2nd Edition) 原出版社: Sams 作者: ...

  7. Linux网络编程入门 (转载)

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  8. Linux网络编程必看书籍推荐

    首先要说讲述计算机网络和TCP/IP的书很多. 先要学习网络知识才谈得上编程 讲述计算机网络的最经典的当属Andrew S.Tanenbaum的<计算机网络>第五版,这本书难易适中. &l ...

  9. [转] - Linux网络编程 -- 网络知识介绍

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

随机推荐

  1. 蓝桥T291(BFS + 输出路径)

    http://lx.lanqiao.org/problem.page?gpid=T291 学霸的迷宫   时间限制:1.0s   内存限制:256.0MB      问题描述 学霸抢走了大家的作业,班 ...

  2. 2个比较经典的PHP加密解密函数分享

    项目中有时我们需要使用PHP将特定的信息进行加密,也就是通过加密算法生成一个加密字符串,这个加密后的字符串可以通过解密算法进行解密,便于程序对解密后的信息进行处理. 最常见的应用在用户登录以及一些AP ...

  3. Protocol Buffer技术详解(Java实例)

    Protocol Buffer技术详解(Java实例) 该篇Blog和上一篇(C++实例)基本相同,只是面向于我们团队中的Java工程师,毕竟我们项目的前端部分是基于Android开发的,而且我们研发 ...

  4. linux ftp命令(转)

    此命令需要安装ftp, yum install ftp 1. 连接ftp服务器 格式:ftp [hostname| ip-address]a)在linux命令行下输入: ftp 192.168.1.1 ...

  5. include(thinkphp常用内置标签)

    变量输出使用普通标签就足够了,但是要完成其他的控制.循环和判断功能,就需要借助模板引擎的标签库功能了,系统内置标签库的所有标签无需引入标签库即可直接使用. XML标签有两种,包括闭合标签和开放标签,一 ...

  6. bootstrap-select搜索框输入中文

    bootstrap-select 的搜索框无法输入中文,解决办法: 删除源码中这两行代码 that.$lis.not('.hidden, .divider, .dropdown-header').eq ...

  7. UML用例图总结

    用例图主要用来描述“用户.需求.系统功能单元”之间的关系.它展示了一个外部用户能够观察到的系统功能模型图. [用途]:帮助开发团队以一种可视化的方式理解系统的功能需求. 用例图所包含的元素如下: 1. ...

  8. 微信和WeChat的合并月活跃账户达6.97亿

    腾讯最新财报显示,微信和WeChat的合并月活跃账户于2015年底达6.97亿,同比增长39%.2016年初春节假期期间,通过微信支付收发的红包数量仅在6天内就超过320亿,同比增长9倍. 腾讯网络广 ...

  9. Commando War

    Commando War“Waiting for orders we held in the wood, word from the front never cameBy evening the so ...

  10. RootKit学习之 IDT Hook

    0x00 前言  IDT(Interrupt Descriptor Table)中断描述符表,中断就是停下现在的活动,去完成新的任务.一个中断可以起源于软件或硬件.比如,出现页错误,调用IDT中的0x ...