Linux网络编程实例详解

合集下载

Linux网络编程学习之select详细讲解

Linux网络编程学习之select详细讲解

Linux网络编程学习之select()详解select系统调用是用来让我们的程序监视多个文件句柄(file descriptor)的状态变化的。

程序会停在select这里等待,直到被监视的文件句柄有某一个或多个发生了状态改变。

文件在句柄在Linux里很多,如果你man某个函数,在函数返回值部分说到成功后有一个文件句柄被创建的都是的,如man socket可以看到“On success, a file descriptor for the new socket is returned.”而man 2 open可以看到“open() and creat() return the new file descriptor”,其实文件句柄就是一个整数,看socket函数的声明就明白了:int socket(int domain, int type, int protocol);当然,我们最熟悉的句柄是0、1、2三个,0是标准输入,1是标准输出,2是标准错误输出。

0、1、2是整数表示的,对应的FILE *结构的表示就是stdin、stdout、stderr,0就是stdin,1就是stdout,2就是stderr。

比如下面这两段代码都是从标准输入读入9个字节字符:#include <stdio.h>#include <unistd.h>#include <string.h>int main(int argc, char ** argv){char buf[10] = "";read(0, buf, 9); /* 从标准输入0 读入字符*/fprintf(stdout, "%s\n", buf); /* 向标准输出stdout 写字符*/return 0;}/* **上面和下面的代码都可以用来从标准输入读用户输入的9个字符** */#include <stdio.h>#include <unistd.h>#include <string.h>int main(int argc, char ** argv){char buf[10] = "";fread(buf, 9, 1, stdin); /* 从标准输入stdin 读入字符*/write(1, buf, strlen(buf));return 0;}继续上面说的select,就是用来监视某个或某些句柄的状态变化的。

Linux命令进阶使用lsof进行文件和网络连接查看

Linux命令进阶使用lsof进行文件和网络连接查看

Linux命令进阶使用lsof进行文件和网络连接查看在Linux系统中,lsof(List Open Files)是一款非常强大的命令行工具,它能够帮助我们查看当前系统中打开的文件和网络连接信息。

通过使用lsof命令,我们可以获取文件的路径、文件描述符、进程ID 以及与之相关联的网络连接等信息。

本文将介绍lsof命令的使用方法及其常见参数,以及通过实际案例来演示lsof命令的应用场景。

一、lsof命令的基本用法lsof的基本用法非常简单,只需要在终端中键入lsof命令即可查看当前系统中打开的文件和网络连接信息。

以下是一些常用的lsof命令参数:1. 查看指定进程ID打开的文件和网络连接我们可以通过"-p"参数指定一个进程ID来查看该进程打开的文件和网络连接信息。

例如,要查看进程ID为12345的进程打开的文件和网络连接信息,我们可以使用以下命令:```lsof -p 12345```2. 查看指定用户打开的文件和网络连接如果我们想查看特定用户打开的文件和网络连接信息,可以使用"-u"参数指定用户名。

例如,要查看用户名为"root"的用户打开的文件和网络连接信息,可以使用以下命令:```lsof -u root```3. 查看指定文件打开的进程如果我们想要知道某个文件被哪个进程打开了,可以使用"-f"参数指定文件路径。

例如,要查看文件"/var/log/syslog"被哪个进程打开了,可以使用以下命令:```lsof -f /var/log/syslog```4. 查看指定端口的网络连接要查看某个指定端口的网络连接信息,可以使用"-i"参数指定端口号。

例如,要查看端口号为80的网络连接信息,可以使用以下命令:```lsof -i :80```二、lsof命令的常见参数除了上述介绍的基本用法外,lsof还有一些常见参数,下面将介绍几个常用的参数:1. "-c"参数(查看指定命令相关的文件和网络连接)使用"-c"参数可以查看与指定命令相关的文件和网络连接信息。

Linux网络编程之sockaddr与sockaddr_in,sockaddr_un结构体详细讲解

Linux网络编程之sockaddr与sockaddr_in,sockaddr_un结构体详细讲解

sockaddrstruct sockaddr {unsigned short sa_family; /* address family, AF_xxx */char sa_data[14]; /* 14 bytes of protocol address */};sa_family是地址家族,一般都是“AF_xxx”的形式。

好像通常大多用的是都是AF_INET。

sa_data是14字节协议地址。

此数据结构用做bind、connect、recvfrom、sendto等函数的参数,指明地址信息。

但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构sockaddr_insockaddr_in(在netinet/in.h中定义):struct sockaddr_in {short int sin_family; /* Address family */unsigned short int sin_port; /* Port number */struct in_addr sin_addr; /* Internet address */unsigned char sin_zero[8]; /* Same size as struct sockaddr */};struct in_addr {unsigned long s_addr;};typedef struct in_addr {union {struct{unsigned char s_b1,s_b2,s_b3,s_b4;} S_un_b;struct {unsigned short s_w1,s_w2;} S_un_w;unsigned long S_addr;} S_un;} IN_ADDR;sin_family指代协议族,在socket编程中只能是AF_INETsin_port存储端口号(使用网络字节顺序)sin_addr存储IP地址,使用in_addr这个数据结构sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。

linux socket编程基础(必读)

linux  socket编程基础(必读)
void bzero(void * s,int n):将参数 s 指定的内存的前 n 个字节设置 为0,通常它用来将套接字地址清0。
(2) void bcopy(const void * src,void * dest,int n):从参数 src 指定 的内存区域拷贝指定数目的字节内容到参数 dest 指定的内存区域。
在调用函数 connect 之前,客户机需要指定服务器进程的套接字地址。客户 机一般不需要指定自己的套接字地址(IP 地址和端口号),系统会自动从1024 至5000的端口号范围内为它选择一个未用的端口号,然后以这个端口号和本机 的 IP 地址填充这个套接字地址。
客户机调用函数 connect 来主动建立连接。这个函数将启动 TCP 协议的3次 握手过程。在建立连接之后或发生错误时函数返回。连接过程可能出现的错误情 况有:
(2) 如果远程 TCP 协议返回一个 RST 数据段,函数立即以错误返回,错 误类型为 ECONNREFUSED。当远程机器在 SYN 数据段指定的目的端口号处
没有服务进程在等待连接时,远程机器的 TCP 协议将发送一个 RST 数据段,向 客户机报告这个错误。客户机的 TCP 协议在接收到 RST 数据段后不再继续发送 SYN 数据段,函数立即以错误返回。
(3) int bcmp(const void * s1,const void * s2,int n):比较参数 s1指 定的内存区域和参数 s2指定的内存区域的前 n 个字节内容,如果相同则返回0, 否则返回非0。
注:以上函数的原型定义在 strings.h 中。 以 mem 开头的函数有: (1) void * memset(void * s,int c,size_t n):将参数 s 指定的内存区 域的前 n 个字节设置为参数 c 的内容。 (2) void * memcpy(void * dest,const void * src,size_t n):功能同 bcopy (),区别:函数 bcopy()能处理参数 src 和参数 dest 所指定的区域有重叠的 情况,memcpy()则不能。 (4) int memcmp(const void * s1,const void * s2,size_t n):比较参 数 s1和参数 s2指定区域的前 n 个字节内容,如果相同则返回0,否则返回非0。 注:以上函数的原型定义在 string.h 中。 9、 基本套接字函数 (1) socket() #include<sys/types.h> #include<sys/socket.h>

Linux的SOCKET编程详解

Linux的SOCKET编程详解

Linux的SOCKET编程详解1. 网络中进程之间如何通信进程通信的概念最初来源于单机系统。

由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进程之间既互不干扰又协调一致工作,操作系统为进程通信提供了相应设施,如UNIX BSD有:管道(pipe)、命名管道(named pipe)软中断信号(signal)UNIX system V有:消息(message)、共享存储区(shared memory)和信号量(semaphore)等.他们都仅限于用在本机进程之间通信。

网间进程通信要解决的是不同主机进程间的相互通信问题(可把同机进程通信看作是其中的特例)。

为此,首先要解决的是网间进程标识问题。

同一主机上,不同进程可用进程号(process ID)唯一标识。

但在网络环境下,各主机独立分配的进程号不能唯一标识该进程。

例如,主机A赋于某进程号5,在B机中也可以存在5号进程,因此,“5号进程”这句话就没有意义了。

其次,操作系统支持的网络协议众多,不同协议的工作方式不同,地址格式也不同。

因此,网间进程通信还要解决多重协议的识别问题。

其实TCP/IP协议族已经帮我们解决了这个问题,网络层的―ip地址‖可以唯一标识网络中的主机,而传输层的―协议+端口‖可以唯一标识主机中的应用程序(进程)。

这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。

使用TCP/IP协议的应用程序通常采用应用编程接口:UNIX BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰),来实现网络进程之间的通信。

就目前而言,几乎所有的应用程序都是采用socket,而现在又是网络时代,网络中进程通信是无处不在,这就是我为什么说―一切皆s ocket‖。

TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。

Linux网络编程-2-大小端及IP地址转换相关函数

Linux网络编程-2-大小端及IP地址转换相关函数

Linux⽹络编程-2-⼤⼩端及IP地址转换相关函数⼤端 & ⼩端⼤⼩端之定义计算机系统是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8bit。

在⼏乎所有的机器上,对于跨越多字节的程序对象,往往都是被连续存储的,对象的地址为所使⽤的字节中最⼩的地址。

在多字节的程序对象中,对不同的字节有两种排列⽅式:⼤端和⼩端。

(⼤⼩端之争就如打鸡蛋从⼤头打还是从⼩头打,没有实际意义。

⼤⼩端的起源也是这个,狗头)⼤端模式:是指数据的⾼字节保存在内存的低地址中,⽽数据的低字节保存在内存的⾼地址中。

(⾼地址存低位)⼩端模式:是指数据的⾼字节保存在内存的⾼地址中,⽽数据的低字节保存在内存的低地址中。

(⾼地址存⾼位,对应到内存中读是个反的)假如32位宽(uint32_t)的数据0x12345678,从地址0x08004000开始存放:地址⼩端存放内容⼤端存放内容0x08004003(⾼地址)0x120x78 0x080040020x340x56 0x080040010x560x34 0x08004000(低地址)0x780x12⼤⼩端之实例判断本机⼤⼩端的⽅法:#include <stdio.h>void byteorder(){union{short value;char union_bytes[ sizeof( short ) ];} test;test.value = 0x0102;if ( ( test.union_bytes[ 0 ] == 1 ) && ( test.union_bytes[ 1 ] == 2 ) ){printf( "big endian\n" );}else if ( ( test.union_bytes[ 0 ] == 2 ) && ( test.union_bytes[ 1 ] == 1 ) ){printf( "little endian\n" );}else{printf( "unknown...\n" );}}int main() {byteorder();}⼤端模式:Sun、PowerPC、IBM⼩端模式:x86、DECARM既可以⼯作在⼤端模式,也可以⼯作在⼩端模式,取决于特定的操作系统。

linux网络编程之SSL

linux网络编程之SSL

一服务器源代码#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <sys/types.h>#include <netinet/in.h>#include <sys/socket.h>#include <sys/wait.h>#include <unistd.h>#include <arpa/inet.h>#include <openssl/ssl.h>#include <openssl/err.h>#define MAXBUF 1024/************关于本文档*********************************************filename: ssl-server.c*purpose: 演示利用OpenSSL 库进行基于IP层的SSL 加密通讯的方法,这是服务器端例子*wrote by: zhoulifa(zhoulifa@) 周立发()Linux爱好者Linux知识传播者SOHO族开发者最擅长C语言*date time:2007-02-02 19:40*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途* 但请遵循GPL*Thanks to:Google*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!*********************************************************************/int main(int argc, char **argv){int sockfd, new_fd;socklen_t len;struct sockaddr_in my_addr, their_addr;unsigned int myport, lisnum;char buf[MAXBUF + 1];SSL_CTX *ctx;if (argv[1])myport = atoi(argv[1]);elsemyport = 7838;if (argv[2])lisnum = atoi(argv[2]);elselisnum = 2;/* SSL 库初始化*/SSL_library_init();/* 载入所有SSL 算法*/OpenSSL_add_all_algorithms();/* 载入所有SSL 错误消息*/SSL_load_error_strings();/* 以SSL V2 和V3 标准兼容方式产生一个SSL_CTX ,即SSL Content Text */ ctx = SSL_CTX_new(SSLv23_server_method());/* 也可以用SSLv2_server_method() 或SSLv3_server_method() 单独表示V2 或V3标准*/if (ctx == NULL) {ERR_print_errors_fp(stdout);exit(1);}/* 载入用户的数字证书,此证书用来发送给客户端。

Linux操作系统应用编程课件(完整版)

Linux操作系统应用编程课件(完整版)

2.Linux操作系统的发行版
Linux操作系统发行版实际就是Linux内核加上外围实用程序 组成的一个大软件包。相对于Linux操作系统的内核版本,发行版 的版本号随发布者的不同而不同,与Linux操作系统内核的版本号 是相对独立的。因此把SUSE、RedHat、Ubuntu、Slackware等直 接称为Linux是不确切的,它们是Linux操作系统的发行版。更确 切地说,应该将它们称为“以Linux为核心的操作系统软件包”。
Shell是Linux操作系统的一种用户界面,它作为操作系统 的“外壳”,为用户提供使用操作系统的接口。Shell主要有以 下两大功能特点。
(1)Shell是一个命令解释器,它拥有自己内建的Shell命令集。 (2)Shell的另一个重要特性是它自身就是一种解释型的程序设 计语言。
当用户成功登录Linux系统后,系统将执行一个Shell程序。 正是Shell进程提供了命令提示符。作为默认值,Shell对普通用 户用“$”作提示符,对超级用户(root)用“#”作提示符。
1.4.4 联机手册
联机手册命令man可向用户提供系统中各种命令、系统调用、 库函数和重要系统文件的详细说明,包括名字、使用语法、功能 描述、应用实例和相关参考文件等。其格式如下:
$ man [拥有哪个级别的帮助。 -k:查看和命令相关的所有帮助。
查看who命令的详细说明示例如下。 $ man who
Linux操作系统 应用编程
本章主要介绍Linux文件系统,包括文件系统的结构、文 件的定义与分类、目录与文件操作命令、文件的权限管理等, 让读者对Linux文件系统有一定的认识和理解,为后文的学习 打下基础。
2.1.1 组织结构
Linux操作系统中所有文件存储在文件系统中,文件被组织 到一棵“目录树”中,其文件系统层次结构(树状目录结构)如 图2.1所示。树根在该层次结构的顶部,树根的下方衍生出子目 录分支。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Linux网络编程实例详解本文介绍了在Linux环境下的socket编程常用函数用法及socket编程的一般规则和客户/服务器模型的编程应注意的事项和常遇问题的解决方法,并举了具体代码实例。

要理解本文所谈的技术问题需要读者具有一定C语言的编程经验和TCP/IP方面的基本知识。

要实习本文的示例,需要Linux下的gcc编译平台支持。

Socket定义网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。

Socket也具有一个类似于打开文件的函数调用—Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。

常用的Socket类型有两种:流式Socket —SOCK_STREAM和数据报式Socket—SOCK_DGRAM。

流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP 服务应用。

Socket编程相关数据类型定义计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。

Intenet上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数据时就需要进行转换。

我们要讨论的第一个结构类型是:struct sockaddr,该类型是用来保存socket信息的:struct sockaddr {unsigned short sa_family;char sa_data[14]; };sa_family一般为AF_INET;sa_data则包含该socket的IP地址和端口号。

另外还有一种结构类型:struct sockaddr_in {short int sin_family;unsigned short int sin_port;struct in_addr sin_addr;unsigned char sin_zero[8];};这个结构使用更为方便。

sin_zero(它用来将sockaddr_in结构填充到与struct sockaddr 同样的长度)应该用bzero()或memset()函数将其置为零。

指向sockaddr_in的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向sockaddr_in的指针转换为指向sockaddr的指针;或者相反。

sin_family通常被赋AF_INET;in_port和sin_addr应该转换成为网络字节优先顺序;而sin_addr则不需要转换。

我们下面讨论几个字节顺序转换函数:htons()--"Host to Network Short" ; htonl()--"Host to Network long"ntohs()--"Network to Host Short" ; ntohl()--"Network to Host Long"在这里,h表示"host",n表示"network",s表示"short",l表示"long"。

打开socket描述符、建立绑定并建立连接socket函数原型为:int socket(int domain, int type, int protocol);domain参数指定socket的类型:SOCK_STREAM或SOCK_DGRAM;protocol通常赋值“0”。

Socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。

一旦通过socket调用返回一个socket描述符,你应该将该socket与你本机上的一个端口相关联(往往当你在设计服务器端程序时需要调用该函数。

随后你就可以在该端口监听服务请求;而客户端一般无须调用该函数)。

Bind函数原型为:int bind(int sockfd,struct sockaddr *my_addr, int addrlen);Sockfd是一个socket描述符,my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;addrlen常被设置为sizeof(struct sockaddr)。

最后,对于bind函数要说明的一点是,你可以用下面的赋值实现自动获得本机IP地址和随机获取一个没有被占用的端口号:my_addr.sin_port = 0;my_addr.sin_addr.s_addr = INADDR_ANY;通过将my_addr.sin_port置为0,函数会自动为你选择一个未占用的端口来使用。

同样,通过将my_addr.sin_addr.s_addr置为INADDR_ANY,系统会自动填入本机IP地址。

Bind()函数在成功被调用时返回0;遇到错误时返回“-1”并将errno置为相应的错误号。

另外要注意的是,当调用函数时,一般不要将端口号置为小于1024的值,因为1~1024是保留端口号,你可以使用大于1024中任何一个没有被占用的端口号。

Connect()函数用来与远端服务器建立一个TCP连接,其函数原型为:int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);Sockfd是目的服务器的sockt描述符;serv_addr是包含目的机IP地址和端口号的指针。

遇到错误时返回-1,并且errno中包含相应的错误码。

进行客户端程序设计无须调用bind(),因为这种情况下只需知道目的机器的IP地址,而客户通过哪个端口与服务器建立连接并不需要关心,内核会自动选择一个未被占用的端口供客户端来使用。

Listen()——监听是否有服务请求在服务器端程序中,当socket与某一端口捆绑以后,就需要监听该端口,以便对到达的服务请求加以处理。

int listen(int sockfd,int backlog);Sockfd是Socket系统调用返回的socket描述符;backlog指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待accept()它们(参考下文)。

cklog对队列中等待服务的请求的数目进行了限制,大多数系统缺省值为20。

当listen遇到错误时返回-1,errno被置为相应的错误码。

故服务器端程序通常按下列顺序进行函数调用:socket(); bind(); listen();accept()——连接端口的服务请求。

当某个客户端试图与服务器监听的端口连接时,该连接请求将排队等待服务器accept()它。

通过调用accept()函数为其建立一个连接,accept()函数将返回一个新的socket描述符,来供这个新连接来使用。

而服务器可以继续在以前的那个socket上监听,同时可以在新的socket描述符上进行数据send()(发送)和recv()(接收)操作:int accept(int sockfd, void *addr, int *addrlen);sockfd是被监听的socket描述符,addr通常是一个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机的信息(某台主机从某个端口发出该请求);addrten通常为一个指向值为sizeof(struct sockaddr_in)的整型指针变量。

错误发生时返回一个-1并且设置相应的errno值。

Send()和recv()——数据传输这两个函数是用于面向连接的socket上进行数据传输。

Send()函数原型为:int send(int sockfd, const void *msg, int len, int flags);Sockfd是你想用来传输数据的socket描述符,msg是一个指向要发送数据的指针。

Len是以字节为单位的数据的长度。

flags一般情况下置为0(关于该参数的用法可参照man 手册)。

char *msg = "Beej was here!"; int len,bytes_sent; ... ...len = strlen(msg); bytes_sent = send(sockfd, msg,len,0); ... ...Send()函数返回实际上发送出的字节数,可能会少于你希望发送的数据。

所以需要对send()的返回值进行测量。

当send()返回值与len不匹配时,应该对这种情况进行处理。

recv()函数原型为:int recv(int sockfd,void *buf,int len,unsigned int flags);Sockfd是接受数据的socket描述符;buf是存放接收数据的缓冲区;len是缓冲的长度。

Flags也被置为0。

Recv()返回实际上接收的字节数,或当出现错误时,返回-1并置相应的errno 值。

Sendto()和recvfrom()——利用数据报方式进行数据传输在无连接的数据报socket方式下,由于本地socket并没有与远端机器建立连接,所以在发送数据时应指明目的地址,sendto()函数原型为:int sendto(int sockfd, const void *msg,int len,unsigned int flags, const struct sockaddr *to, int tolen);该函数比send()函数多了两个参数,to表示目地机的IP地址和端口号信息,而tolen常常被赋值为sizeof (struct sockaddr)。

Sendto函数也返回实际发送的数据字节长度或在出现发送错误时返回-1。

Recvfrom()函数原型为:int recvfrom(int sockfd,void *buf,int len,unsigned int lags,struct sockaddr *from,int *fromlen);from是一个struct sockaddr类型的变量,该变量保存源机的IP地址及端口号。

fromlen 常置为sizeof (struct sockaddr)。

当recvfrom()返回时,fromlen包含实际存入from中的数据字节数。

Recvfrom()函数返回接收到的字节数或当出现错误时返回-1,并置相应的errno。

应注意的一点是,当你对于数据报socket调用了connect()函数时,你也可以利用send()和recv()进行数据传输,但该socket仍然是数据报socket,并且利用传输层的UDP服务。

相关文档
最新文档