1.什么是socket

  socket(套接字),简单来说是IP地址与端口(port)的组合,可以与远程主机的应用程序进行通信通过IP地址可以确定一台主机,而通过端口则可以确定某一个应用程序。IP+端口则可以完全确定某台主机的某个应用。socket起源于UNIX,类似一种特殊文件,可以进行打开,关闭,读写操作。总而言之,有了socket就可以与网络上的主机进行通信。

2.TCP/UDP 协议

  要进行网络通信,就要进行一定规则约束,TCP/UDP就是这样的协议,规定了通信的规则。

  TCP是可靠的,面向连接的双向数据传输协议。可靠是指数据不会重复,也不会丢失。每当发送方发送一个数据给接收方时,如果接收方接收到了该数据,则会发送确认信息给发送方表示”我已经收到该数据了,你可以发送下一条数据了“,收到确认信息后,发送方才会发送下一条数据。这样就可以确定信息的无误。双向传输指双方都可以作为发送方或接收方。

  UDP是不可靠的,无连接的双向传输协议。UDP协议只管发送数据,不会确认你有没有收到,只负责发,不负责确认,所以是不可靠的。UDP适用于传输视频之类的,视频就算丢失一两帧也不会有太大影响。

  socket既可以是基于TCP,也可以是基于UDP的,根据需求选择即可。

3.一个简单的通信程序

  用一个简单的例子来说明socket的用法。用socket写的程序一般分为,两部分,一个是服务器端,一个是客户端.

  下面说明服务器端创建过程

  1).首先要有套接字才能进行通信,创建套接字的函数是

 

 int socket(int af, int type, int protocol);

  af:表示地址族,常用的有AF_INET表示使用IPV4地址,AF_INET6表示使用IPV6地址

  type:传输类型常用有SOCK_STREAM ,SOCK_DGRAM,流式传输,报文传输

  protocol:要使用的协议常用有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示TCP,UDP协议

  返回一个套接字描述符,也就是一个整型。

  2).用bind()函数确定socket各种属性

 int bind(int sock, struct sockaddr *addr, socklen_t addrlen);  

  sock:要绑定的套接字

  addr:SOCKADDR地址结构体,里面包含使用的协议,IP地址,端口等。要自己设定

  addrlen:SOCKADDR的大小,可以用sizeof()获取

  下面的代码展示创建一个套接字与绑定的过程

 //使用IPV4地址,TCP协议
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
SOCKADDR_IN addr;
addr.sin_addr.S_un.S_addr = htonl(ADDR_ANY);//表示任何的ip过来连接都接受
addr.sin_family = AF_INET;//使用IPV4地址
addr.sin_port = htons();//使用6666号端口
bind(serverSocket, &addr, sizeof(SOCKADDR));//将套接字与端口6666,设定接收的ip绑定

 3).listen函数监听

  设定属性后,服务器端就可以开始监听了,监控是否有客户端请求连接。

  函数原型

 int listen(int sock, int backlog); 

  sock:套接字

  backlog:允许多少个客服端连接

 4).accept函数等待连接

  accept是一个阻塞函数,如果没有客户端清求连接会一直等待在这里

 int accept(int sock, struct sockaddr *addr, socklen_t *addrlen); 

  sock:套接字,

  addr:SOCKADDR 结构体

  addrlen:addr的长度,可以用sizeof求到

  要注意该函数的返回值,它会返回一个新的套接字,这个新的套接字是用来与客户端通信的套接字,之前那个套接字是监听的套接字,要分清楚。

  5).send/recv发送/接收信息

  与客户端连接成功后就可以进行通信了。可以通信的函数有write/read,send/recv等,这里介绍send/recv

 int send(int sockfd, const char *buf, size_t len, int flags);

 int recv(int sockfd, char*buf, size_t len, int flags);

  sockfd:套接字

  buf:发送数据的缓冲区

  len:发送数据的长度

  flags:标志,一般为零

  6).closesocket函数关闭套接字

  closesocket()关闭套接字

  下面是一个完整的服务器端的代码

 #include<stdio.h>
#include<WinSock2.h>
#pragma comment (lib,"ws2_32.lib")
int main()
{
SOCKET serverSocket;//监视的套接字
SOCKET newSocket;//用来通信的套接字
SOCKADDR_IN newAddr;//保存客户端的socket地址信息
SOCKADDR_IN addr;//地址结构体,包括ip port(端口) WSADATA data;
WORD version;//socket版本
int info;
char buf[];//数据缓冲区
/*
在使用socket之前要进行版本的设定和初始化
看不懂不用管
*/
version = MAKEWORD(, );//设定版本
info = WSAStartup(version, &data);
/*应用程序或DLL只能在一次成功的WSAStartup()调用之后
才能调用进一步的Windows Sockets API函数。
根据版本初始化 windows socket,返回0表示成功
*/ if (info != )
{
printf("初始化失败\n");
return -;
}
if (LOBYTE(data.wVersion) != || HIBYTE(data.wVersion) != )
{
printf("加载失败\n");
WSACleanup();
return ;
}
//创建套接字,使用TCP协议
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
addr.sin_addr.S_un.S_addr = htonl(ADDR_ANY);//表示任何的ip过来连接都接受
addr.sin_family = AF_INET;//使用ipv4的地址
addr.sin_port = htons();//设定应用占用的端口
bind(serverSocket, &addr, sizeof(SOCKADDR));//将套接字与端口6666,接收的ip绑定
listen(serverSocket, );//开始监听,是否有客服端请求连接
printf("开始监听,等待连接..........\n");
int len = sizeof(SOCKADDR);
newSocket=accept(serverSocket, (SOCKADDR*)&newAddr,&len);
sprintf(buf, "欢迎:%s 的用户连接", inet_ntoa(newAddr.sin_addr));
send(newSocket, buf, , );//发送信息
printf("连接成功,开始发送信息..........\n");
recv(newSocket, buf, , );//接收信息
printf("接收到的信息为:%s\n", buf);
closesocket(newSocket);//关闭套接字
}

  运行结果

  

  客户端例子

  客户端与服务器端不同,服务器端是等待连接的,而客户端是主动连接的,所以客户端没有listen函数监听,也没有accept函数等待连接。

  客户端有一个connect函数用于主动连接服务器端。其余差不多

 int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen);

  sock:套接字

  serv_addr:SOCKADDR结构体

  addrlen:serv_addr长度,可以用sizeof得到

  客户端代码

  

 #include<stdio.h>
#include<WinSock2.h>
#pragma comment(lib,"Ws2_32.lib") int main()
{
SOCKET clientSocket;
SOCKADDR_IN addr;
int len;
char buf[];
int info;
WSADATA data;
WORD version;
//设定版本,与初始化
version = MAKEWORD(, );
info = WSAStartup(version, &data);
if (info != )
{
printf("初始化失败\n");
return -;
}
if (LOBYTE(data.wVersion) != || HIBYTE(data.wVersion) != )
{
printf("加载失败\n");
WSACleanup();
return ;
} clientSocket = socket(AF_INET, SOCK_STREAM, );//创建套接字
//要连接的服务器的ip,因为现在服务器端就是本机,所以写本机ip
//127.0.0.1一个特殊的IP地址,表示是本机的IP地址
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
//端口要与服务器相同,不然找不到
addr.sin_port = htons();
//用IPV4地址
addr.sin_family = AF_INET;
//主动连接服务器
connect(clientSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR));
//接收服务发送的数据
recv(clientSocket, buf, , );//接收数据
printf("服务器发送的信息是:%s\n", buf);
sprintf(buf, "%s","你好,服务器");
//发送数据
send(clientSocket, buf, , );
//关闭套接字
closesocket(clientSocket);
return ; }

  先启动服务器,再启动客户端。一次简单的通信就完成了

 

把这个简单的例子做出来,对于socket应该会有初步的认识,最起码应该学会怎么用。

下次利用socket写个简单的聊天程序,进一步加深对socket的认识。

【网络编程01】socket的基础知识-简单网络通信程序的更多相关文章

  1. java 网络编程(一)---基础知识和概念了解

    java 为用户提供了十分完善的网络功能: 1. 获取网络上的各种资源(URL) 2. 与服务器建立连接和通信(ServerSocket和Socket) 3. 无连接传递本地数据(DatagramSo ...

  2. java基础-网络编程(Socket)技术选型入门之NIO技术

    java基础-网络编程(Socket)技术选型入门之NIO技术 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传统的网络编程 1>.编写socket通信的MyServer ...

  3. 网络编程01 · 艺

    Web Socket和Socket 套接字,实际就是传输层的接口.用于抽象传输层,隐藏细节.一对套接字可以进行通信. Web Socket,是基于TCP协议的.类似于,http. 为什么需要Web S ...

  4. python网络编程01 /C/S架构|B/S架构、网络通信原理、五层协议、七层协议简述、端口映射技术

    python网络编程01 /C/S架构|B/S架构.网络通信原理.五层协议.七层协议简述.端口映射技术 目录 python网络编程01 /C/S架构|B/S架构.网络通信原理.五层协议.七层协议简述. ...

  5. 网络编程与socket套接字

    网络编程与socket套接字 传输层 PORT协议 port是一种接口,数据通过它在计算机和其他设备(比如打印机,鼠标,键盘或监视器)之间,网络之间和其他直接连接的计算机之间传递 TCP协议 ​ 传输 ...

  6. python网络编程-01

    python网络编程 1.socket模块介绍 ①在网络编程中的一个基本组件就是套接字(socket),socket是两个程序之间的“信息通道”. ②套接字包括两个部分:服务器套接字.客户机套接字 ③ ...

  7. python 网络编程:socket(二)

    上节地址:Python网络编程:socket 一.send和sendall区别 send,sendall         ret = send('safagsgdsegsdgew') #send 发送 ...

  8. Android 网络编程基础之简单聊天程序

    前一篇讲了Android的网络编程基础,今天写了一个简单的聊天程序分享一下 首先是服务端代码: package com.jiao.socketdemo; import java.io.Buffered ...

  9. 从零探索Java网络编程01之 TCP/IP 与 Socket

    最近完成了几项比较简单的项目, 终于是在996里偷了点闲暇时光, 想着来研究研究些啥吧?  一个普通的控制台日志映入了我的眼帘(孽缘呀): (图中使用 SpringBoot 的 log4j 来输出日志 ...

随机推荐

  1. 前端工程师眼中的Docker

    笔者最近在整理 Node.js 操作各数据库的方法,却不料遇到一个很棘手的问题:很多数据库,都需要同时下载 Server 端和 Client 端,并进行相应的配置,着实是麻烦.那有没有方法可以省去这些 ...

  2. mysql 如果没有密码 就不能远程连接

    mysql 如果没有密码 就不能远程连接

  3. Java注解 看这一篇就够了

    注解 1.概念 注解:说明程序的.给计算机看的 注释:用文字描述程序的.给程序员看的 注解的定义:注解(Annotation),也叫元数据.一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性 ...

  4. Ext.grid 分页

    1. 定义变量,存储,每页显示多少条数据 var itemsPage = 25; 2.grid数据源 //列表源 var oStore = Ext.create('Ext.data.Store', { ...

  5. maven中的pom配置文件一——spring,mybatis,oracle,jstl,json,文件上传

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...

  6. 038.集群网络-K8S网络实现

    一 Kubernetes网络实现 1.1 Kubernetes网络优势 在实际的业务场景中,业务组件之间的关系十分复杂,微服务的理念更是让应用部署的粒度更加细小和灵活.为了支持业务应用组件的通信,Ku ...

  7. python基础--深浅拷贝copy

    拷贝是音译的词,其实他是从copy这个英文单词音译过来的,那什么是copy? copy其实就是复制一份,也就是所谓的抄一份.深浅copy其实就是完全复制一份,和部分复制一份的意思. 1.赋值运算 l1 ...

  8. 数据库表结构查询SQL

    今天给大家送上两个SQL查询的方法,也许在项目中你都用过,但是,没关系,仅仅记录下,以便后面不用去查找.针对与经常写SQL的同行来说,应该是非常简单的. 查询表结构数据 SELECT t.COLUMN ...

  9. Unity 游戏框架:资源管理神器 ResKit

    此篇文章准备了将近两周的时间,写了改,改了删.之前有朋友反馈,上一个文章太冗长了,影响阅读体验,这一讲就走个精简路线.所以只要不是很重要的内容就都删减掉了. 文章分两个部分,第一部分是原理,第二部分是 ...

  10. [深入学习C#] 匿名函数、委托和Lambda表达式

    匿名函数 匿名函数(Anonymous Function)是表示“内联”方法定义的表达式.匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型(了解详情).匿名函数转换的计算取 ...