码迷,mamicode.com
首页 > 系统相关 > 详细

Linux下网络编程

时间:2020-05-09 16:51:32      阅读:101      评论:0      收藏:0      [点我收藏+]

标签:serve   传输协议   blog   tail   add   方法   sizeof   display   ESS   

目录

一、相关协议的介绍

二、socket实现C/S通信

三、常用函数介绍  

  1、socket()---用于服务端和客户端
  2、bind()---用于服务端  涉及到大端和小端模式
  3、listen()---用于服务端
  4、accetp()---用于服务端
  5、connect()----用于客户端

 

一、相关协议的介绍

 

二、socket实现C/S通信

 

三、常用函数介绍

1、socket()---用于服务端和客户端

函数头文件及函数原型:

1 #include <sys/types.h> /* See NOTES */
2 #include <sys/socket.h>
3 int socket(int domain, int type, int protocol);

参数及返回值说明:

技术图片
 1 domain:
 2     AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址
 3     AF_INET6 与上面类似,不过是来用IPv6的地址
 4     AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用
 5 type:
 6     SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
 7     SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
 8     SOCK_SEQPACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。
 9     SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
10     SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序
11 protocol:
12     传0 表示使用默认协议。
13 返回值:
14     成功:返回指向新创建的socket的文件描述符,失败:返回-1,设置errno
View Code

socket()说明:

技术图片
1 socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调用出错则返回-1。对于IPv4,domain参数指定为AF_INET。对于TCP协议,type参数指定为SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定为SOCK_DGRAM,表示面向数据报的传输协议。protocol参数的介绍从略,指定为0即可。
View Code

2、bind()---用于服务端

函数作用:是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号。

函数头文件及函数原型

1 #include <sys/types.h> /* See NOTES */
2 #include <sys/socket.h>
3 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数及返回值说明:

1 sockfd:
2     socket文件描述符
3 addr:
4     构造出IP地址加端口号
5 addrlen:
6     sizeof(addr)长度
7 返回值:
8     成功返回0,失败返回-1, 设置errno

bind()第二个参数sockaddr是一个结构体,原型如下:

1 struct sockaddr {  
2      sa_family_t sin_family;//地址族
3     char sa_data[14]; //14字节,包含套接字中的目标地址和端口信息               
4 }; 

由于sockaddr结构体中的成员sa_data将目标地址(目标IP地址)和端口混在一起了,所以不使用这个结构体,而是要另外一个结构体socketaddr_in,最后将sockaddr_in强制转换一下即可,sockaddr_in结构体原型如下:

 1 struct sockaddr_in{
 2     sa_family_t     sin_family;  //地址族(Address Family)
 3     uint16_t        sin_port;    //16位TCP/UDP端口号
 4     struct in_addr  sin_addr;    //32位ip地址
 5     char            sin_zero[8];  //不使用
 6 };
 7 
 8 struct in_addr{
 9     In_addr_t s_addr;   //32位ipv4地址
10 };

由于在TCP/UDP/IP协议中规定使用大端存储方式(网络自己序),而在我们的电脑中使用的是小端模式,因此需要转换函数,做存储模式的转换:

 1  #include <arpa/inet.h>
 2 
 3 //将主机字节序转换为网络字节序
 4  unit32_t htonl (unit32_t hostlong);
 5  unit16_t htons (unit16_t hostshort);
 6  //将网络字节序转换为主机字节序
 7  unit32_t ntohl (unit32_t netlong);
 8  unit16_t ntohs (unit16_t netshort);
 9 
10  说明:h -----host;n----network ;s------short;l----long

大端和小端模式参考博客

使用方法如下:

1 struct sockaddr_in server;
2 memset(&server, 0, sizeof(server));                //先将结构体清零
3 server.sin_family = AF_INET;                       // 地址类型 - ipv4
4 server.sin_port = htons(8888);  
5 server.sin_addr.s_addr = htonl(INADDR_ANY);        //htons(a)表示将在主机中的小端存储方式转换为网络中的大端存储方式  s表示shrot  
6 int ret = bind(lfd, (struct sockaddr*)&server, sizeof(server));  //同理htonl()  l表示long

INADDR_ANY,这个宏表示本地的任意IP地址,因为服务器可能有多个网卡,每个网卡也可能绑定多个IP地址,这样设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP地址

3、listen()---用于服务端

头文件及函数原型

1 #include <sys/types.h> /* See NOTES */
2 #include <sys/socket.h>
3 int listen(int sockfd, int backlog);

参数说明

1 sockfd:
2     socket文件描述符
3 backlog:
4     排队建立3次握手队列和刚刚建立3次握手队列的链接的最大数
5     或者是可以创建连接的最大数

返回值

listen()成功返回0,失败返回-1

listen()函数说明

技术图片
1 /*
2 典型的服务器程序可以同时服务于多个客户端,当有客户端发起连接时,服务器调用的accept()返回并接受这个连接,如果有大量的客户端发起连接而服务器来不及处理,尚未accept的客户端就处于连接等待状态,listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态,如果接收到更多的连接请求就忽略。listen()成功返回0,失败返回-1。
3 */
View Code

4、accetp()---用于服务端

头文件即函数原型

1 #include <sys/types.h>         /* See NOTES */
2 #include <sys/socket.h>
3 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数说明及函数返回值

sockdf:
    socket文件描述符
addr:
    传出参数,返回链接客户端地址信息,含IP地址和端口号
addrlen:
    传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小
返回值:
    成功返回一个新的socket文件描述符,用于和客户端通信,通过这个读新的文件描述符就可以得到客户端发来的信息,失败返回-1,设置errno

函数说明

技术图片
1 /*
2 三方握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。addr是一个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是一个传入传出参数(value-result argument),传入的是调用者提供的缓冲区addr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)。如果给addr参数传NULL,表示不关心客户端的地址。
3 */
View Code

使用方法

1 struct sockaddr_in client;
2 socklen_t len = sizeof(client);
3 int cfd = accept(lfd, (struct sockaddr*)&client, &len);  //如果没有客户端请求连接,则阻塞在这里,其中client为传出参数,包含了客户端的ip和端口号
4 if(cfd == -1)
5 {
6     perror("accept error");
7     exit(1);
8 }

accept()的返回值是另外一个文件描述符connfd,之后与客户端之间就通过这个connfd通讯,最后关闭connfd断开连接,通过cfd读取客户端发来的信息的方法:

1 char buf[1024] = {0};
2 int len = read(cfd, buf, sizeof(buf));
3 //len=-1读失败
4 //len=0客户端关闭
5 //len>0读成功

5、connect()----用于客户端

头文件及函数原型

1 #include <sys/types.h>                     /* See NOTES */
2 #include <sys/socket.h>
3 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数及函数返回值说明

1 sockdf:
2     socket文件描述符
3 addr:
4     传入参数,指定服务器端地址信息,含IP地址和端口号
5 addrlen:
6     传入参数,传入sizeof(addr)大小
7 返回值:
8     成功返回0,失败返回-1,设置errno

函数说明

1 /*
2 客户端需要调用connect()连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址。connect()成功返回0,出错返回-1。
3 */

 

Linux下网络编程

标签:serve   传输协议   blog   tail   add   方法   sizeof   display   ESS   

原文地址:https://www.cnblogs.com/YiYA-blog/p/12858530.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!