网络通信实际是应用进程之间的通信,而要完整的描述一个应用进程在网络中的位置必须用 IP+端口;

Socket就是一种在网络中进行数据通信的一种抽象描述。它是一种协议,本地地址,本地端口的抽象。

Socket它是面向C/S模型而设计的。

Windows Sockets 规范,又称为WinSock,是微软联合其他几家公司推出的Windows 操作系统环境下的网络编程接口。它继承了UNIX下的Socket,是Windows下标准、通用的TCP/IP编程接口。

目前推出了1.1版本,这个版本只支持TCP/IP协议;2.x以后,支持更多的网络与协议规范。比如无线网络通信等。

版本 1.1  头文件 WINSOCK.h   链接库文件  wsock32.lib  动态库文件  Winsock.dll

版本 2.2  头文件  WINSOCK2.h 链接库文件  ws2_32.lib   动态库文件 WS2_32.dll

Winsock 提供了两种形式的Socket:流式套接字(stream socket)和 数据报套接字(datagram socket)。其中,流式套接字只TCP协议,数据报套接字支持UDP协议。

以下是基于套接字的TCP协议实现过程:

基于流式套接字的编程模式如下:

基于数据报套接字的编程模式如下:

下面这个是一个特例,也就是说在UDP中也可以由connect(),通过connect()将本地的UDP 的socket与远程的socket连接起来。

4、“有连接”的UDP

虽然UDP是无连接的,但是也可以通过调用connect()将本地的UDP socket FD与一个远程的UDP socket FD连接起来——只需要指定这个远程sockFD的地址,假设这个地址是sockaddr_in remoteSockAddr,代码如下:

  1. if (connect(sockFD,
  2. (sockaddr*)&remoteSockAddr,
  3. sizeof(remoteSockAddr)) < 0) {
  4. sockClass::error_info("connect() failed.");
  5. }

复制代码

建立连接后的UDP RecvQ就不会将非来自remoteSockAddr的数据包收入。

请注意UDP的connect()与TCP的 connect()很不相同,TCP是连接服务器的监听socket,并且会阻塞直到服务器调用accept()。一般的说法,UDP的连接并不会改变 UDP的各种特点,比如,即使连接,UDP也不知道远程主机是否在线连接或者是否断开——但是,我个人认为,改变了本机的RecvQ接收数据包的过滤机制,也就改变了UDP原本可以接收来自任何地址信息的属性。

如果希望断开UDP的连接,需要使用一个特定的“断开”地址,代码如下:

  1. sockaddr descon_sock_addr;
  2. memset(&descon_sock_addr, 0, sizeof(descon_sock_addr));
  3. descon_sock_addr.sa_family = AF_UNSPEC;
  4. if (connect(sockFD,
  5. &descon_sock_addr,
  6. sizeof(descon_sock_addr)) < 0) {
  7. sockClass::error_info("des connect() failed.");
  8. }

复制代码

请注意这里的地址族AF_UNSPEC直接赋值给了一个sockaddr结构。我试过,使用sockaddr_in也是可以的,但是无论是哪个结构,首先都得将整个结构对象清零,否则可能报错。

注:我们可以利用WinSock API函数也可以利用MFC提供的WinSock封装类。

有一点小疑惑,网络编程中为何不需要客户端IP地址及端口号即:不需要客户端套接字地址。

因为,我们在计算机网络中,我们在传数据时,它会自动带上本机的IP地址。比如,客户端向服务器端发送某个

数据报时,它肯定会在报头加上源IP地址,而目的IP地址及端口号这个就需要自己手动加入数据报中,不然,当路由器进行解析

的时候,就不知道该往哪个网络里面的主机里面传送了。

根据上面的介绍,我想大家一定想练练手,好,下面我将自己的demo提供给大家。最后会提供给大家一个链接的。

废话不多说,直接看结果:以下是UDP传输结果,上面是服务器端程序,显示的数据是从客户端发过去的。

第二个界面与上面相反,客户端程序,显示的数据从服务器端发过来的。当然,我们在实际编程时,可以有的放矢,

有时候不需要回传数据进行验证之类的。不是双工模式,而是单工模式。

以下是TCP的执行结果:

先打开服务器端,显示如下:

再开启客户端,显示如下:

不多解释,一切全在代码中。

socketserver.cpp文件:

 // socketserver.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include "conio.h"
#include "windows.h"
//socket头文件
#include "winsock.h"
//socket库的lib
#pragma comment(lib,"ws2_32.lib") void TCPServer()
{
/***************创建服务器端套接字SOCKET*******************/
/*******socket()函数解释:IP协议族,数据流方式,TCP协议****/
SOCKET socksvr=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET == socksvr)
{
return;
}
/*************建立服务器端套接字地址***********************/
/********************绑定IP和端口号******************/
struct sockaddr_in svraddr = {};
svraddr.sin_family = AF_INET;//代表internet协议族
/**htons()函数解释:是将u_short型变量从主机字节顺序变换为TCP/IP网络字节顺序**/
/**这里涉及大小端系统问题。intel处理器是低位字节在****************/
/**较低地址存放,而高位字节在较高地址存放,与网络字节顺序相反,故需要调换过来****/
svraddr.sin_port = htons();
//htonl()函数是将u_long型变量从主机字节顺序变为TCP/IP网络字节顺序。
svraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//此宏为0,当前机器上任意IP地址,也可以指定当前机的ip和端口。
//绑定,将服务器端套接字与服务器端套接字地址绑定
bind(socksvr,(struct sockaddr *)&svraddr,sizeof(svraddr));//指定名字,类型,长度。绑定套接字。
//侦听
listen(socksvr,SOMAXCONN);//第一个参数是套接字,第二个参数是等待连接队列的最大长度。
//等候客户端建立连接
printf("等候客户端.......\n");
//建立客户端套接字地址,主要是为了接收客户端返回参数之用
struct sockaddr_in clientaddr = {};
int nLen = sizeof(clientaddr);
//以下是建立客户端套接字并建立连接函数。有一个确认的过程。
//注:后面填的是客户端地址长度的地址。
SOCKET sockclient = accept(socksvr,(struct sockaddr*)&clientaddr,&nLen);//建立连接函数
printf("客户端已连接\n");
/********以下是数据收发部分*********/
//先接收后发送,由上面知,数据已在sockclient中,我们只需读此结构便可知晓数据
CHAR szText[] = {};
//接收缓冲区数据
recv(sockclient,szText,,); //接收函数,一直处于侦听模式,等待服务器端发送数据的到来。
printf("%s\n",szText);
CHAR szSend[] = "Hello Client";
send(sockclient,szSend,sizeof(szSend),);//发送函数。
/****accept/recv/send 都是堵塞函数,需要把所以的数据都接收完或发送完才可以工作。*****/
// getch();//暂停一下
//关闭socket
closesocket(sockclient);
closesocket(socksvr); } void UDPServer()
{
//创建socket
SOCKET socksvr = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(INVALID_SOCKET == socksvr)
{
return ;
}
//服务器套接字地址
//绑定ip与端口,先定义端口等一些信息。
struct sockaddr_in svraddr = {};
svraddr.sin_family = AF_INET;
svraddr.sin_port = htons();
svraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
bind(socksvr,(struct sockaddr*)&svraddr,sizeof(svraddr)); /********以下是数据收发部分*********/
//客户端套接字地址,接收客户端数据时需要用,数据都在套接字里面。
CHAR szRecv[] = {};
struct sockaddr_in clientaddr = {};
int nLen = sizeof(clientaddr);
/*下面函数前四个参数同TCP接收数据函数recv()一样,后两个中,一个是返回发送*******/
/*数据地址的主机的地址,包括IP地址以及端口号,最后一个为地址长度的地址。*******/
/*此函数中,先是服务器端的套接字,后是客户端的地址*/
//从后往前读此函数
recvfrom(socksvr,szRecv,,,(struct sockaddr*)&clientaddr,&nLen);//构造ip地址
printf("%s\n",szRecv); //注1:该程序也可以向客户端发送数据。
//注2:服务器端中,必须也是先接收后发送,不然,我们无法知道客户端的地址。下面函数中clientaddr已知晓
CHAR szSend[] = "hello udp client";
//从前往后读此函数
sendto(socksvr,szSend,,,(struct sockaddr*)&clientaddr,nLen);//发送时构造ip地址和端口。 // getch();//可以暂停显示,这个很重要。 //关闭socket
closesocket(socksvr); } int main(int argc, _TCHAR* argv[])
{
//初始化socket库
WSADATA wsa = {}; //WinSockApi 取WSA+DATA组成套接字结构体
WSAStartup(MAKEWORD(,),&wsa);
//服务器
TCPServer();
//UDPServer();
//清理套接字资源
WSACleanup();
getch();//暂停一下 return ;
}

socketclient.cpp 文件:

 // socketclint.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include "conio.h"
#include "windows.h"
#include "winsock.h"
#pragma comment(lib,"ws2_32.lib") void TCPClient()
{
//创建socket
SOCKET sockclient = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET == sockclient)
{
return;
}
//连接服务器,建立服务器端套接字地址
struct sockaddr_in addr = {};
addr.sin_family = AF_INET;
addr.sin_port = htons();
//对于inet_addr()函数,它是把“xxx.xxx.xxx.xxx”形式表示的IPV4地址,转换为IN_ADDR结构体能够
//接收的形式(unsigned long型,因为IN_ADDR结构体中的负责接收的S_addr成员变量的类型是unsigned long型)
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//本机ip //向服务器发出连接请求,当然我们也可以通过connet函数的返回值判断到底有无连接成功。
int iRetVal = connect(sockclient,(struct sockaddr*)&addr,sizeof(addr));
if(SOCKET_ERROR == iRetVal)
{
printf("服务器连接失败!");
closesocket(sockclient);
return;
}
printf("服务器连接成功!\n");
//数据收发
CHAR szSend[] = "hello server"; //客户端 先发后收
send(sockclient,szSend,sizeof(szSend),); //发送函数,可以通过返回值判断发送成功与否。 //接收服务器回传的数据
CHAR szRecv[] = {};
recv(sockclient,szRecv,,); //接收函数
printf("%s\n",szRecv);//表示以字符串的格式输出服务器端发送的内容。 // getch();//暂停一下
//关闭socket
closesocket(sockclient);
}
void UDPClient()
{
//创建SOCKET ,ip协议族,数据报方式,udp协议。
SOCKET sockclient = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(INVALID_SOCKET == sockclient)
{
return ;
}
//数据收发,服务器端套接字地址
struct sockaddr_in svraddr = {};
svraddr.sin_family = AF_INET;
svraddr.sin_port = htons();
svraddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//指定服务器端的IP与端口。
CHAR szSend[] = "hello udp server";
/*此函数先是客户端的套接字,然后是服务器端地址*/
//简单理解为:从函数前面的客户端套接字的发送数据缓存区中将数发送给服务器端地址
sendto(sockclient,szSend,,,(struct sockaddr*)&svraddr,sizeof(svraddr));//发送时构造ip地址和端口。 //注:该程序也可以接收服务器端回传的数据。
CHAR szRecv[];
//简单理解为:从函数后面的服务器端地址中取数到客户端套接字的接收缓冲区szRecv中
int len = sizeof(svraddr);
recvfrom(sockclient,szRecv,,,(struct sockaddr*)&svraddr,&len);
printf("%s \n",szRecv);
//关闭socket
closesocket(sockclient);
} int main(int argc, _TCHAR* argv[])
{
//初始化socket库
WSADATA wsa = {};
WSAStartup(MAKEWORD(,),&wsa);
//tcp客户端
TCPClient();
//UDPClient();
//清理套接字资源
WSACleanup();
getch(); return ;
}

已传至PUDN,文件名1_1-socket,用户可自行下载。

Socket概述及TCP/IP的C++实现的更多相关文章

  1. Socket网络编程(TCP/IP/端口/类)和实例

    Socket网络编程(TCP/IP/端口/类)和实例 原文:C# Socket网络编程精华篇 转自:微冷的雨 我们在讲解Socket编程前,先看几个和Socket编程紧密相关的概念: TCP/IP层次 ...

  2. Linux系统编程(30)—— socket编程之TCP/IP协议

    在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣经中上帝打乱了各地人的口音,让他们无法合作一样.计算机使用者意识到,计算机 ...

  3. 第一章 概述——1.TCP/IP设计遵循的两个原则

    1.端到端原则(end-to-end principle) 当我们设计一个大的系统(如操作系统或协议族)时,随之而来的一个问题通常是在什么位置实现某个功能.影响TCP/IP协议族设计的一个重要原则是端 ...

  4. Python中的socket网络编程(TCP/IP,UDP)讲解

    在网络编程中的一个基本组件就是套接字(socket).套接字基本上是两个端点的程序之间的"信息通道".程序可能分布在不同的计算机上,通过套接字互相发送信息.套接字包括两个:服务器套 ...

  5. tcp/ip详解 卷1 -- 协议概述

    第一章 概述 分层 TCP/IP 通常被认为是一个四层协议系统. 每一层负责不同的功能. 链路层, 也成为数据链路层或者网络接口层. 通常包括 操作系统中的设备驱动程序和计算机中对应的网络接口卡. 主 ...

  6. socket http tcp ip 区别联系

    功能是实现继承复用.刚才做了一个简要的概述,里面有一些常用的概念,这里做个简短的概念普及介绍:(1),TCP/IP------TPC/IP协议是传输层协议,主要解决数据如何在网络中传输.(2),Soc ...

  7. 门面模式的典型应用 Socket 和 Http(post,get)、TCP/IP 协议的关系总结

    门面模式的一个典型应用:Socket 套接字(Socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元.它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息: 连接使用的 ...

  8. TCP/IP、Http、Socket、XMPP-从入门到深入

    TCP/IP.Http.Socket.XMPP-从入门到深入 终极iOS程序猿 2016-12-29 18:27 为了便于大家理解和记忆,我们先对这几个概念进行的介绍,然后分析他们的不同,再进行详细的 ...

  9. ios开发网络知识 TCP,IP,HTTP,SOCKET区别和联系

    TCP,IP,HTTP,SOCKET区别和联系 网络由下往上分为:        对应 物理层-- 数据链路层-- 网络层--                       IP协议 传输层--     ...

随机推荐

  1. java课后作业-4

    一.编写一个方法,使用以上算法生成指定数目(比如1000个)的随机整数. public class suiji { private static final int N = 200; private ...

  2. 【03】react 之 创建component

    React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归:具体的三种方式: 函数式定义的无状态组件 es5原生方式React.createClass定义的组件 es6形式的ext ...

  3. 【12】vue-router 之路由重定向

    看之前的项目,突然发现一个不算bug的bug,之前也是一直没有想到,现在发现之后越来越觉得有必要改掉, 项目用的是vue做的,自然切换用的就是路由,一级路由包括:首页.记录和个人中心,二级路由是在记录 ...

  4. pat 团体天梯赛 L3-015. 球队“食物链”

    L3-015. 球队“食物链” 时间限制 1000 ms 内存限制 262144 kB 代码长度限制 8000 B 判题程序 Standard 作者 李文新(北京大学) 某国的足球联赛中有N支参赛球队 ...

  5. HTML 文档之 Head 最佳实践

    语言 在 html 标签中通过 lang 属性进行明确的语言声明,将会有助于翻译,英文.简体中文和繁体中文网页所属性值如下: <html lang="en"> < ...

  6. win10下怎么配置以KDiff3作为merge tool和diff tool

    系统环境: OS: Windows 10 Git 2.6.1.windows.1 KDiff3 0.9.98 (64 bit) 具体代码如下: git config --global --add me ...

  7. C#TreeView读取Xml,TreeView导出到Xml

    实现功能有1.根据Xml生成TreeView2.双击修改节点3.右键添加子节点或添加要节点4.右键删除当前选择的节点5.将修改后的TreeView重新生成Xml文档 其实这个主要是实现 了Xml生成T ...

  8. JavaScripts广告轮播图以及定时弹出和定时隐藏广告

    轮播图: 函数绑定在body标签内 采用3张图,1.jpg   2.jpg  3.jpg  利用定时任务执行设置图片属性 src  利用for循环可以完成3秒一次 一替换. 定时弹出广告: 由于bod ...

  9. 【原创】Word2010 清除样式

    使用场景         有时候我们在网页上面粘贴一些精华文章或者从去整理别人已经完成的word的时候,会发现它自带的格式,可能并不是我们所理想的格式,所以此时就不得不去重新编辑其格式,但是word里 ...

  10. 常用公共DNS服务器地址

    DNS,全称Domain Name System,即域名解析系统,帮助用户在互联网上寻找路径,它在互联网的作用是把域名转换成为网络可以识别的IP地址.目前国内电信运营商通过使用DNS劫持和DNS污染的 ...