Winsock编程原理——面向连接

Windows Sockets使用套接字进行编程,套接字编程是面向客户端/服务器模型而设计的,因此系统中需要客户端和服务器两个不同类型的进程,根据连接类型的不同,对于面向连接的TCP服务和无连接的UDP服务,服务器分别采取不同的处理操作来对客户提供服务。

面向连接

服务器
socket() -> bind() -> listen() -> accept() -> recv()/send() -> closesocket();
创建套接字,绑定IP和端口,侦听,接收连接,收发消息,关闭连接
客户端
socket() -> connet() -> send()/recv() -> closesocket();
创建套接字,连接服务器,发收消息,关闭连接
 
一对一的模式,一个服务器, 一个客户端
 
 /*
服务器端代码
*/ #include<Winsock2.h>
#include<stdio.h>
#include<stdlib.h>
#pragma comment(lib,"ws2_32.lib")
#define PORT 5000 void main()
{
int port = PORT; //端口
WSADATA wsaData; //存储系统传回的关于Winsock的资料
SOCKET sListen, sAccept; //套接字
int iLen; //客户地址长度
int iSend; //发送数据长度
char buf[] = "Hello, How are you!"; //需要发送的信息
struct sockaddr_in serv, cliet; //服务器、客户的地址 if (WSAStartup(MAKEWORD(, ), &wsaData) != ) //函数WSAStartup用以打开Winsock
{
printf("Winsock load failed\n");
return;
} sListen = socket(AF_INET, SOCK_STREAM, ); //创建套接字,TCP协议
if (sListen == INVALID_SOCKET) //socket调用成功返回套接字对象,失败返回INVALID_SOCKET
{
printf("socket failed:%d\n", WSAGetLastError());
return;
} serv.sin_family = AF_INET; //网络中标识不同设备使用的地址类型,对于IP地址,类型是AF_INET
serv.sin_port = htons(port); //socket对应的端口号
serv.sin_addr.s_addr = htonl(INADDR_ANY); //封装了IP地址
if (bind(sListen, (LPSOCKADDR)&serv, sizeof(serv)) == SOCKET_ERROR) //绑定套接字
{
printf("bind() failed:%d\n", WSAGetLastError());
return;
} if (listen(sListen, ) == SOCKET_ERROR) //监听
{
printf("listen() failed:%d\n", WSAGetLastError());
return;
} iLen = sizeof(cliet); //初始化客户地址长度 while () //进入循环,等待客户连接请求
{
sAccept = accept(sListen, (struct sockaddr*)&cliet, &iLen); //客户端的套接字
if (sAccept == INVALID_SOCKET) //接受连接请求失败
{
printf("accept() failed:%d\n", WSAGetLastError());
break;
}
//输出客户端IP、端口
printf("accept() client IP:[%s], port:[%d]\n", inet_ntoa(cliet.sin_addr), ntohs(cliet.sin_port)); //给连接的客户发送消息
iSend = send(sAccept, buf, sizeof(buf), );
if (iSend == SOCKET_ERROR)
{
printf("send() failed:%d\n", WSAGetLastError());
break;
}
else if (iSend == )
break;
else
printf("send() byte:%d\n", send); closesocket(sListen); //关闭套接字
closesocket(sAccept); //关闭套接字
WSACleanup(); //关闭Winsock
}
while ();
}

server

 /*
客户端程序
*/
#include<WinSock2.h>
#include<stdio.h>
#pragma comment(lib,"ws2_32.lib")
#define PORT 5000
#define BUFFER 1024 void main(int argc,char *argv[])
{
WSADATA wsaData;
SOCKET client;
int port = PORT;
int iLen; //从服务器接收的数据长度
char buf[BUFFER]; //接收数据的缓冲
struct sockaddr_in serv; //服务器端地址
memset(buf, , sizeof(buf)); //接受数据缓冲区初始化 if (WSAStartup(MAKEWORD(, ), &wsaData) != ) //函数WSAStartup用以打开Winsock
{
printf("Winsock load failed\n");
return;
} serv.sin_family = AF_INET; //需要连接服务器地址信息,AF_INET表示IP协议
serv.sin_port = htons(port); //端口
// serv.sin_addr.s_addr = inet_addr(argv[1]); //IP地址,转为二进制表示的字节IP地址,argv表示cmd下输入的参数
serv.sin_addr.s_addr = inet_addr("10.100.211.224");
client = socket(AF_INET, SOCK_STREAM, ); //客户端套接字,流套接字表示使用TCP协议
if (client == INVALID_SOCKET) //创建套接字失败
{
printf("socket() failed:%d\n", WSAGetLastError());
return;
} //连接服务器
if (connect(client, (struct sockaddr*)&serv, sizeof(serv)) == INVALID_SOCKET)
{
printf("connet() failed:%d\n", WSAGetLastError);
return;
}
else
{
iLen = recv(client, buf, sizeof(buf), ); //从服务器接收数据
if (iLen = )
return;
else if (iLen == SOCKET_ERROR)
{
printf("recv() failed:%d\n", WSAGetLastError());
return;
}
printf("recv() data from server:%s\n", buf);
} closesocket(client); //关闭套接字
WSACleanup; //关闭Winsock // system("pause"); //程序暂停
printf("press any key to continue"); //让程序等待
while ();
}

client

加入多线程机制,一个服务器,多个客户端

 /*
服务器端代码
*/ #include<Winsock2.h>
#include <windows.h>
#include<stdio.h>
#include<stdlib.h>
#pragma comment(lib,"ws2_32.lib")
#define PORT 5000
class MySocket
{
private:
SOCKET accept;
struct sockaddr_in clientAddr;
public:
MySocket(SOCKET a, struct sockaddr_in c)
{
accept = a;
clientAddr = c;
}
void setAccept(SOCKET a)
{
accept = a;
}
void setClientAddr(struct sockaddr_in c)
{
clientAddr = c;
}
SOCKET getAccept()
{
return accept;
}
struct sockaddr_in getClientAddr()
{
return clientAddr;
}
};
DWORD WINAPI ThreadFuc(LPVOID lparam)
{
MySocket* mSocket = (MySocket*)lparam; //接收主线程传来的参数
char buf[] = "Hello, How are you!"; //需要发送的信息
int iSend = ;
//输出客户端IP、端口
printf("accept() client IP:[%s], port:[%d]\n", inet_ntoa(mSocket->getClientAddr().sin_addr), ntohs(mSocket->getClientAddr().sin_port));
//给连接的客户发送消息
iSend = send(mSocket->getAccept(), buf, sizeof(buf), );
if (iSend == SOCKET_ERROR)
{
printf("send() failed:%d\n", WSAGetLastError());
}
else if (iSend == )
printf("send() failed,no message send successfully\n");
else
printf("send() byte:%d\n", send);
closesocket(mSocket->getAccept()); //关闭套接字
return ;
} void main()
{
int port = PORT; //端口
WSADATA wsaData; //存储系统传回的关于Winsock的资料
SOCKET sListen, sAccept; //套接字
int iLen; //客户地址长度
struct sockaddr_in serv, cliet; //服务器、客户的地址 if (WSAStartup(MAKEWORD(, ), &wsaData) != ) //函数WSAStartup用以打开Winsock
{
printf("Winsock load failed\n");
return;
} sListen = socket(AF_INET, SOCK_STREAM, ); //创建套接字,TCP协议
if (sListen == INVALID_SOCKET) //socket调用成功返回套接字对象,失败返回INVALID_SOCKET
{
printf("socket failed:%d\n", WSAGetLastError());
return;
} serv.sin_family = AF_INET; //网络中标识不同设备使用的地址类型,对于IP地址,类型是AF_INET
serv.sin_port = htons(port); //socket对应的端口号
serv.sin_addr.s_addr = htonl(INADDR_ANY); //封装了IP地址
if (bind(sListen, (LPSOCKADDR)&serv, sizeof(serv)) == SOCKET_ERROR) //绑定套接字
{
printf("bind() failed:%d\n", WSAGetLastError());
return;
} if (listen(sListen, ) == SOCKET_ERROR) //监听
{
printf("listen() failed:%d\n", WSAGetLastError());
return;
} iLen = sizeof(cliet); //初始化客户地址长度 while () //进入循环,等待客户连接请求
{
sAccept = accept(sListen, (struct sockaddr*)&cliet, &iLen); //客户端的套接字
if (sAccept == INVALID_SOCKET) //接受连接请求失败
{
printf("accept() failed:%d\n", WSAGetLastError());
break;
}
else
{
MySocket* mSocket = new MySocket(sAccept, cliet);
HANDLE thread = CreateThread(NULL, NULL, ThreadFuc, mSocket, NULL, NULL);
// closesocket(sAccept);不能关闭,关闭则不行。
}
}
closesocket(sListen); //关闭套接字
WSACleanup(); //关闭Winsock
while ();
}

server

 /*
客户端程序
*/
#include<WinSock2.h>
#include<stdio.h>
#pragma comment(lib,"ws2_32.lib")
#define PORT 5000
#define BUFFER 1024 void main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKET client;
int port = PORT;
int iLen; //从服务器接收的数据长度
char buf[BUFFER]; //接收数据的缓冲
struct sockaddr_in serv; //服务器端地址
memset(buf, , sizeof(buf)); //接受数据缓冲区初始化 if (WSAStartup(MAKEWORD(, ), &wsaData) != ) //函数WSAStartup用以打开Winsock
{
printf("Winsock load failed\n");
return;
} serv.sin_family = AF_INET; //需要连接服务器地址信息,AF_INET表示IP协议
serv.sin_port = htons(port); //端口
// serv.sin_addr.s_addr = inet_addr(argv[1]); //IP地址,转为二进制表示的字节IP地址,argv表示cmd下输入的参数
serv.sin_addr.s_addr = inet_addr("192.168.0.21");
client = socket(AF_INET, SOCK_STREAM, ); //客户端套接字,流套接字表示使用TCP协议
if (client == INVALID_SOCKET) //创建套接字失败
{
printf("socket() failed:%d\n", WSAGetLastError());
return;
} //连接服务器
if (connect(client, (struct sockaddr*)&serv, sizeof(serv)) == INVALID_SOCKET)
{
printf("connet() failed:%d\n", WSAGetLastError);
return;
}
else
{
iLen = recv(client, buf, sizeof(buf), ); //从服务器接收数据
if (iLen = )
return;
else if (iLen == SOCKET_ERROR)
{
printf("recv() failed:%d\n", WSAGetLastError());
return;
}
printf("recv() data from server:%s\n", buf);
} closesocket(client); //关闭套接字
WSACleanup; //关闭Winsock // system("pause"); //程序暂停
printf("press any key to continue"); //让程序等待
while ();
}

client

Winsock编程原理——面向连接的更多相关文章

  1. socket编程原理

    socket编程原理 1.问题的引入 1) 普通的I/O操作过程: UNIX系统的I/O命令集,是从Maltics和早期系统中的命令演变出来的,其模式为打开一读/写一关闭(open-write-rea ...

  2. 第1章 网络编程基础(2)——Socket编程原理

    Socket编程原理 Socket是网络通信端点的一种抽象,它提供了一种发送和接收数据的机制. 流socket(SOCK_STREAM):双向.有序.无重复.并且无记录边界 数据报Socket(SOC ...

  3. Winsock编程基础介绍 .

    相信很多人都对网络编程感兴趣,下面我们就来介绍,在网络编程中应用最广泛的编程接口Winsock API. 使用Winsock API的编程,应该了解一些TCP/IP的基础知识.虽然你可以直接使用Win ...

  4. 【VS开发】socket编程原理

    socket编程原理 1.问题的引入 1) 普通的I/O操作过程: UNIX系统的I/O命令集,是从Maltics和早期系统中的命令演变出来的,其模式为打开一读/写一关闭(open-write-rea ...

  5. NetBIOS与Winsock编程接口

    最近在看网络编程方面的书,由于不是通信专业出身的,以前理解的网络体系感觉就是tcp/ip,最近工作上接触到了一些光环网等乱七八糟的东西,有些基本的LC.SC连接器都不认识.花时间看了下计算机网络体系结 ...

  6. Winsock 编程流程

    近期看了<Window程序设计>感觉在网络方面讲的不错,讲的非常通俗易懂.与大家一同交流 转载请注明出处:http://blog.csdn.net/u010484477谢谢^_^ 使用 W ...

  7. Delphi下的WinSock编程

    一.定址        要通过Winsock建立通信,必须了解如何利用指定的协议为工作站定址.Winsock 2引入了几个新的.与协议无关的函数,它们可和任何一个地址家族一起使用:但是大多数情况下,各 ...

  8. Winsock 编程详解

    转载请注明出处!本文地址:https://www.cnblogs.com/teternity/p/WinSock.html Winsock 编程 目录 通用函数讲解 WSAStartup WSACle ...

  9. JavaScript异步编程原理

    众所周知,JavaScript 的执行环境是单线程的,所谓的单线程就是一次只能完成一个任务,其任务的调度方式就是排队,这就和火车站洗手间门口的等待一样,前面的那个人没有搞定,你就只能站在后面排队等着. ...

随机推荐

  1. Djano中static和media文件路径的设置

    对于常用的css.js.image和常用的工具类在django项目中要设置一个全局的路径,对所有的app都可以访问到这个路径下的文件 1在django项目的setting文件中设置对应的static和 ...

  2. 第二节:专做自己是小白——重新认识MySQL 学习记录

    一.安装MySQL的一些知识点 1.进程号是操作系统随机分配,每次启动程序都会有一个新的进程号.    2.mysql服务器进程默认名称MySQL,MySQL客户端进程默认名称mysql.    3. ...

  3. elasticsearch 进行聚合+去重查询

    转载:https://www.jianshu.com/p/c03c3c8bf583 以客户customer为例 我想查询每日的客户数. 先按照日期分桶,然后在桶内按照 姓名来去重 来计算客户数(实际会 ...

  4. 判断是否为PC

    function IsPC() { var userAgentInfo = navigator.userAgent; var Agents = ["Android", " ...

  5. Hadoop中的排序和连接

    MapReduce的全排序 主要是为了保证分区排序,即第一个分区的最后一个Key值小于第二个分区的第一个Key值 与普通的排序仅仅多一个自定义分区类MyPartitioner见自己所写的实验 (设置一 ...

  6. C#基础提升系列——C#委托

    C# 委托 委托是类型安全的类,它定义了返回类型和参数的类型,委托类可以包含一个或多个方法的引用.可以使用lambda表达式实现参数是委托类型的方法. 委托 当需要把一个方法作为参数传递给另一个方法时 ...

  7. 04 SecurityContextHolder与SecurityContext说明

    该篇记录一下SecurityContextHolder与SecurityContext两个类,当然还有与它们关系密码的SecurityContextPersistenceFilter.java这个过滤 ...

  8. 使用C#获取IP地址方法

    C#中如何获取IP地址?,看到问题的时候我也很纠结,纠结的不是这个问题是如何的难回答,而是纠结的是这些问题都是比较基本的常识,也是大家会经常用到的.但是却不断的有人问起,追根究底的原因估计就是没有好好 ...

  9. php is_file()函数 语法

    php is_file()函数 语法 is_file()函数怎么用? php is_file()函数用于判断给定文件名是否为一个正常的文件,语法是bool is_file ( string $file ...

  10. 图与例解读Async/Await

    JavaScript ES7的async/await语法让异步promise操作起来更方便.如果你需要从多个数据库或者接口按顺序异步获取数据,你可能最终写出一坨纠缠不清的promise与回调.然而使用 ...