Socket网络编程

套接字概念Socket本身有“插座”的意思,在Linux环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。与管道类似的,Linux系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传递。套接字的内核实现较为复杂,不宜在学习初期深入学习。在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。套接字通信原理如下图所示:

套接字通讯原理示意在网络通信中,套接字一定是成对出现的。一端的发送缓冲区对应对端的接收缓冲区。我们使用同一个文件描述符索发送缓冲区和接收缓冲区。TCP/IP协议最早在BSD UNIX上实现,为TCP/IP协议设计的应用层编程接口称为socket API。现在的主要内容是socket API,主要介绍TCP协议的函数接口,最后介绍UDP协议和UNIX Domain Socket的函数接口。

网络编程接口1、什么是计算机网络?多个计算机进行通信--->计算机网络。2、计算机通信的复杂度(1)、传输信息的复杂度(种类、内容);(2)、信息的数量(3)、传输距离(干扰...)(4)、信息的安全问题(5)、计算机体系的完整性和封闭性。既要保证计算机的封闭性,又要达成计算机的通信。3、ip地址(1)、IP地址是有限的,需要一种方式将IP地址复用。(2)、IP地址的复用导致了数据传递的复杂性(ATM,存储转发机制;路由机制)。(3)、IP地址过于抽象不方便使用,于是给出了IP地址的人文化转义:域名。(4)、域名只能代表一个IP网络地址,于是就只能代表一个网络上的节点实体。(5)、实际上访问节点的时候,本质上使用的是IP地址,所以就需要将域名转化为IP地址(DNS...)4、IP地址的分类(1)、IPv4地址是4字节的,中间以 . 划分;IPv6地址是16字节的;规定:在IP地址划分上,一般不取全0/全1;IP一般分为5类;A、B、C、D、E,一般常用的IP地址为A类,B类,C类;

A类IP:第一个字节是以0开头0000 0000--->0111 11110~127B类IP:第一个字节是以10开头1000 0000--->1011 1111128~191 C类IP:第一个字节是以110开头 1100 0000--->1101 1111192~223 (2)、子网掩码:就是将网络号设置为1,主机号设置为0(对每一个字节的位进行设置);例:C类IP地址,3个字节网络号和一个字节的主机号;1111 1111 1111 1111 1111 1111 0000 0000 255 . 255 .255 . 0(3)、子网划分:此时就存在C类地址的子网掩码不一定总是255.255.255.0; 这还的看C类IP下面有没有子网划分,有子网划分的话,最后一个字节,也就是主机号可能为2段(01/10)、4段(00/01/10/11)例:192.168.3.11xx xxxx1111 1111 1111 1111 1111 1111 1100 0000此时对应的子网掩码为:255.255.255.192(4)、IOS和TCP/IP模型分析

(5)、端口号port:唯一标识应用程序的编号; 我们之间通过、、邮箱进行收发数据时,没有导致数据的错乱接收,是怎么做到的呢?又是怎么一一对应找到的呢?:通过端口号,识别了电脑上的某一应用程序,也就是找对应的编号。我们在进行数据的发送时:首先通过IP寻找物理计算机,在根据port,寻找对应的应用程序。 (6)、TCP和UDP UDP属于TCP/IP体系中的一部分。TCP协议和UDP协议都属于传输层协议。TCP协议:i>、面向连接的传输协议、可靠的、同步的;ii>、面向连接的网络传输特点:a、需要有一方主动的建立连接,另一方接收连接请求;b、只有建立了连接之后才能够进行数据的传输;c、当数据传输完毕之后,就需要释放连接,由连接的两端来共同决定连接是否保持。UDP协议:a、面向无连接的:即就是在进行数据传输的时候,不需要预先创建一个连接;b、不可靠的:无法知道发送的数据是否能够到达目的,也无法知道什么时候能够到达目的。c、异步的:(7)、TCP的三次握手、四次挥手TCP------->至少3次握手(最后一次防止误按,2次的话,有可能死锁);: 打电话模型模型分析

TCP-------->4次挥手。模型:男女朋友分手模型

通过IP,只能保证物理上的连通,至于收发数据的形式是什么,都不归它管。127.0.0.1:本机回送地址,可作为测试本机使用,不安装网卡也是可以ping通的。5、TCP的编程实现基础的socket编程对TCP的就是下面的步骤:(1)、模型分析

(2)、代码实现utili.h#include<stdio.h>#include<unistd.h>#include<string.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#define SERVER_PORT 9090#define SERVER_IP"127.0.0.1"#define LISTEN_QUEUE5#define BUF_SIZE255服务器端代码:#include"utili.h"//TCPint main(void){int sockSer = socket(AF_INET, SOCK_STREAM, 0); if(sockSer == -1){perror("socket");return -1; } struct sockaddr_in addrSer, addrCli;addrSer.sin_family = AF_INET;addrSer.sin_port = htons(SERVER_PORT);addrSer.sin_addr.s_addr = inet_addr(SERVER_IP);int yes = 1;setsockopt(sockSer, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); //地址、端口的重用socklen_t len = sizeof(struct sockaddr);int res = bind(sockSer, (struct sockaddr *)&addrSer, len);if(res == -1){perror("bind");close(sockSer);return -1; } res = listen(sockSer, LISTEN_QUEUE);if(res == -1){perror("listen");close(sockSer);return -1;}int sockConn;char sendbuf[BUF_SIZE];char recvbuf[BUF_SIZE];while(1){sockConn = accept(sockSer, (struct sockaddr *)&addrCli, &len);if(sockConn == -1){continue; }else{printf("Server Accept Client Connect OK\n");}printf("Ser :>");scanf("%s", sendbuf);if(strncmp(sendbuf, "quit", 4) == 0)break;send(sockConn, sendbuf, strlen(sendbuf)+1, 0);recv(sockConn, recvbuf, BUF_SIZE, 0);printf("Cli :>%s\n", recvbuf);}close(sockSer);return 0;}客户端代码:#include"utili.h"//TCPint main(void){int sockCli = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in addrSer;addrSer.sin_family = AF_INET;addrSer.sin_port = htons(SERVER_PORT);addrSer.sin_addr.s_addr = inet_addr(SERVER_IP);struct sockaddr_in addrCli;addrCli.sin_family = AF_INET;addrCli.sin_port = htons(7070);addrCli.sin_addr.s_addr = inet_addr("192.168.1.155");int yes = 1;setsockopt(sockCli, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); //地址、端口的重用socklen_t len = sizeof(struct sockaddr);int res = bind(sockCli, (struct sockaddr *)&addrCli, len);if(res == -1){perror("bind");close(sockCli);return -1; } res = connect(sockCli, (struct sockaddr*)&addrSer, len);if(res == -1){perror("connect");close(sockCli);return -1;}else{printf("Client Connect Server ok\n");}char sendbuf[BUF_SIZE];char recvbuf[BUF_SIZE];while(1){connect(sockCli, (struct sockaddr*)&addrSer, len);recv(sockCli, recvbuf, BUF_SIZE, 0);printf("Ser :>%s\n", recvbuf);printf("Cli :>");scanf("%s", sendbuf);if(strncmp(sendbuf, "quit", 4) == 0)break;send(sockCli, sendbuf, strlen(sendbuf)+1, 0);}close(sockCli);return 0;}(3)、运行结果

6、UDP的编程实现基础的socket编程对UDP的就是下面的步骤:(1)、模型分析

(2)、代码实现utili.h#include<unistd.h>#include<stdio.h>#include<string.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#define SERVER_PORT9090#define SERVER_IP"127.0.0.1"#define LISTEN_QUEUE5#define BUFFER_SIZE 255服务器端代码:#include"utili.h"int main(){int sockSer = socket(AF_INET, SOCK_DGRAM, 0); if(sockSer == -1){perror("socket");return -1; } struct sockaddr_in addrSer, addrCli;addrSer.sin_family = AF_INET;addrSer.sin_port = htons(SERVER_PORT);addrSer.sin_addr.s_addr = inet_addr(SERVER_IP);socklen_t len = sizeof(struct sockaddr);int res = bind(sockSer, (struct sockaddr*)&addrSer, len);if(res == -1){perror("bind");close(sockSer);return -1; } char sendbuf[BUFFER_SIZE];char recvbuf[BUFFER_SIZE];while(1){recvfrom(sockSer, recvbuf, BUFFER_SIZE, 0, (struct sockaddr*)&addrCli, &len);printf("Cli:>%s\n",recvbuf); printf("Ser:>");scanf("%s",sendbuf);if(strncmp(sendbuf, "quit", 4) == 0){break;}sendto(sockSer, sendbuf, strlen(sendbuf)+1, 0, (struct sockaddr*)&addrCli, len);}close(sockSer);return 0;}客户端代码:#include"utili.h"intmain(){int sockCli = socket(AF_INET, SOCK_DGRAM, 0); if(sockCli == -1){perror("socket");return -1; } struct sockaddr_in addrSer;addrSer.sin_family = AF_INET;addrSer.sin_port = htons(SERVER_PORT);addrSer.sin_addr.s_addr = inet_addr(SERVER_IP);char sendbuf[BUFFER_SIZE];char recvbuf[BUFFER_SIZE];socklen_tlen = sizeof(struct sockaddr);while(1){printf("Cli:>");scanf("%s",sendbuf);if(strncmp(sendbuf, "quit", 4) == 0){ break;} sendto(sockCli, sendbuf, strlen(sendbuf)+1, 0, (struct sockaddr*)&addrSer, len);recvfrom(sockCli, recvbuf, BUFFER_SIZE, 0, (struct sockaddr*)&addrSer, &len);printf("Ser:>%s\n",recvbuf);}close(sockCli);return 0; }(3)、运行结果服务器端截图

客户端截图

服务端的套接字总领全局,不与任何客户端进行通信,为每一个新的客户端所分配一个新的套接字,进行通信。LISTEN_QUEUE:等待队列的大小(最多等待多少队列);UDP:必须先知道服务器在哪。喜欢本文的朋友们,欢迎长按下图关注订阅号编程小兔崽,收看更多精彩内容

http://weixin.qq.com/r/NByrsyHEkXzurWXQ90km (二维码自动识别)

每天进步一点点,如果有用给小编点个赞