windows下socket学习(一)
关于socket的文章,园子里面有很多,其实无非就是 WSAStartup、socket、bind、listen、accept、recv、send(服务端),WSAStartup、socket、connect、send、recv(客户端)的使用。今天第一次看socket,也只学会了socket阻塞模式,即一个服务端对一个客户端,别的客户端想连接也连接不上--个人理解,不知道对不对。
为了解决一(服务端)对多(客户端)的问题,自作聪明在服务端用上了多线程。初步效果还不错:

我晕,1080P的笔记本上截的图,放上来这么大!
上代码,
TCPServer.cpp
/****************************************************************************
/* 文 件 名:server.cpp *
/* 作 者:ZhangXuliang *
/* 日 期:2015/05/24 星期日 11:28 *
/* 版 本 号:V 1.0.0 *
/* 版权说明:Copyright(c)2015 ZXL. All rights reserved. *
/* 描 述:多线程处理Client连接 *
/****************************************************************************/ #define _CRT_SECURE_NO_WARNINGS #include <iostream>
#include <windows.h>
#include <process.h> //#include <WinSock2.h>
#pragma comment(lib,"Ws2_32.lib") #define SERVER_IP "127.0.0.1"
#define SERVER_PORT 9999
#define BUFSIZE (1024) //定义一个结构体,存储客户端的sClient、sockaddr_in结构
typedef struct _ClientStruct
{
SOCKET csSocket;
SOCKADDR_IN csSockAddr_In;
} ClientStruct, *LPClientStruct; //处理后续客户端事件的程序
void ClientEven(PVOID param); using namespace std;
int main()
{
int ErrCode; //错误代码
int addrlen;
WSADATA WSAdata;
SOCKET sServer, sClient;
SOCKADDR_IN saServer, saClient; //初始化
ErrCode = WSAStartup(MAKEWORD(, ), &WSAdata);
if (ErrCode)
{
cout << "WSAStartup()出错!错误代码:#" << ErrCode << endl;
WSACleanup();
return -;
} //创建套接字
sServer = socket(AF_INET, SOCK_STREAM,);
if (INVALID_SOCKET == sServer)
{
cout << "socket()出错!错误代码:#" << WSAGetLastError() << endl;
WSACleanup();
return -;
} //初始化saServer
saServer.sin_family = AF_INET;
saServer.sin_addr.S_un.S_addr = htons(INADDR_ANY);
saServer.sin_port = htons(SERVER_PORT);
//绑定监听IP和端口,以便下面的listen()监听
ErrCode = bind(sServer, (SOCKADDR *)&saServer, sizeof(SOCKADDR_IN));
if (SOCKET_ERROR == ErrCode)
{
cout << "bind()出错!错误代码:#" << WSAGetLastError() << endl;
WSACleanup();
return -;
} //开始监听
ErrCode = listen(sServer, );
if (SOCKET_ERROR == ErrCode)
{
cout << "listen()出错!错误代码:#" << WSAGetLastError() << endl;
WSACleanup();
return -;
}
cout << "正在监听端口:" << SERVER_PORT << endl; while (TRUE)
{
//接受来自客户端的连接请求
addrlen = sizeof(saClient);
sClient = accept(sServer, (SOCKADDR *)&saClient, &addrlen);
if (INVALID_SOCKET == sClient)
{
cout << "accpet()出错!错误代码:#" << WSAGetLastError() << endl;
} //启动一个线程,来处理后续的客户端事件
LPClientStruct lpcsClient = new ClientStruct; //个人觉得这儿用 new 是一个创举啊,因为在启动线程后,如果直接将ClientStruct指针
lpcsClient->csSocket = sClient; //传到ClientEven()中,那么,当有中一个Client接入时,会改变ClientEven中的ClientStruct内容
lpcsClient->csSockAddr_In = saClient; //所以这儿用new,再在线程中delete
_beginthread(ClientEven,, lpcsClient); }
WSACleanup();
return ;
} void ClientEven(PVOID param)
{
int ErrCode; char buf[BUFSIZE] = { };
SYSTEMTIME time;
GetLocalTime(&time);
sprintf(buf, "%4d-%02d-%02d %02d:%02d:%02d", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond); //设置下输出的字体的颜色
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN);
cout << buf << "\t" << inet_ntoa(((LPClientStruct)param)->csSockAddr_In.sin_addr) << ":"
<< ((LPClientStruct)param)->csSockAddr_In.sin_port << "\t接入服务器" << endl;
//还原字体颜色
SetConsoleTextAttribute(hConsole, FOREGROUND_INTENSITY);
//连接成功,先发送一条成功的消息
ErrCode = send(((LPClientStruct)param)->csSocket, "连接服务器成功", strlen("连接到服务器成功!"),);
if (SOCKET_ERROR == ErrCode)
{
cout << "send()出错!错误代码:#" << WSAGetLastError() << endl;
delete (LPClientStruct)param;
_endthread();
} while (TRUE)
{
//接受消息
ZeroMemory(buf, BUFSIZE);
ErrCode = recv(((LPClientStruct)param)->csSocket, buf, sizeof(buf), );
if (SOCKET_ERROR == ErrCode)
{
if (WSAGetLastError() == )
{
SetConsoleTextAttribute(hConsole, FOREGROUND_RED);
cout << inet_ntoa(((LPClientStruct)param)->csSockAddr_In.sin_addr) << ":" << ((LPClientStruct)param)->csSockAddr_In.sin_port << "\t被强制断开连接!" << endl;
SetConsoleTextAttribute(hConsole, FOREGROUND_INTENSITY);
}
else
{
cout << "recv()出错!错误代码:#" << WSAGetLastError() << endl;
} delete (LPClientStruct)param; //退出线程之前先delete前面new的ClientStruct
_endthread();
} cout << inet_ntoa(((LPClientStruct)param)->csSockAddr_In.sin_addr) << ":" << ((LPClientStruct)param)->csSockAddr_In.sin_port << "\t说:" << buf << endl; //反馈消息
//if ((pPipe = _popen(buf, "rt")) != NULL)
//{
// while (!feof(pPipe))
// {
// fgets(szResult, 32, pPipe);
// strcat(buf, szResult);
// if (strlen(buf) == 1024)
// {
// buf[1024] = 'c'; //c --continue
// send(((LPClientStruct)param)->csSocket, buf, sizeof(buf), 0);
// ZeroMemory(buf, BUFSIZE);
// }
// }
// _pclose(pPipe);
//}
//else
// strcpy(buf, "打开匿名管道失败!"); ErrCode = send(((LPClientStruct)param)->csSocket, buf, sizeof(buf), ); if (SOCKET_ERROR == ErrCode)
{
cout << "send()出错!错误代码:#" << WSAGetLastError() << endl; delete (LPClientStruct)param; //退出线程之前先delete前面new的ClientStruct
_endthread();
}
}
delete (LPClientStruct)param; //退出线程之前先delete前面new的ClientStruct
_endthread();
}
下面是TCPClient.cpp
/****************************************************************************
/* 文 件 名:Client.cpp *
/* 作 者:ZhangXuliang *
/* 日 期:2015/05/23 星期六 23:30 *
/* 版 本 号:V 1.0.0 *
/* 版权说明:Copyright(c)2015 ZXL. All rights reserved. *
/* 描 述:Client客户端 *
/****************************************************************************/ #define _CRT_SECURE_NO_WARNINGS #include <iostream>
#include <string> #include <winsock.h>
#pragma comment(lib,"ws2_32.lib") using namespace std; #define BUFSIZE 1024
#define PORT 9999
//#define SERVER_IP "127.0.0.1" int main()
{
WSAData wsaData;
SOCKET sHost;
sockaddr_in addrServ;
char buf[BUFSIZE];
int retVal; if (WSAStartup(MAKEWORD(, ), &wsaData) != )
{
cout << "WSAStartup()失败!" << endl;
return -;
} sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sHost)
{
cout << "socket()出错!" << endl;
WSACleanup();
return -;
} addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(PORT);
addrServ.sin_addr.S_un.S_addr = inet_addr("192.168.1.223"); retVal = connect(sHost, (LPSOCKADDR)&addrServ, sizeof(addrServ));
if (SOCKET_ERROR == retVal)
{
cout << "connect()出错!" << endl;
closesocket(sHost);
WSACleanup();
return -;
}
retVal = recv(sHost, buf, sizeof(buf) + , );
cout << "从服务器接受:" << buf << endl << endl << endl;
while (TRUE)
{
cout << "输入要发给服务器的内容:";
//string msg;
//getline(cin.msg);
char msg[BUFSIZE];
//cin.getline(msg, BUFSIZE);
cin >> msg;
//cout << endl;
ZeroMemory(buf, BUFSIZE);
strcpy(buf, msg); retVal = send(sHost, buf, strlen(buf), );
if (SOCKET_ERROR == retVal)
{
cout << "发送失败!" << endl;
closesocket(sHost);
WSACleanup();
return -;
} retVal = recv(sHost, buf, sizeof(buf) + , );
if (SOCKET_ERROR == retVal)
{
cout << "recv()出错!错误代码:#" << WSAGetLastError() << endl;
closesocket(sHost);
WSACleanup();
return -;
}
cout << "从服务器接受:" << buf << endl << endl; if (strcmp(buf, "quit") == )
{
cout << "quit" << endl;
break;
}
} closesocket(sHost);
WSACleanup(); return ; }
windows下socket学习(一)的更多相关文章
- c++ 网络编程(四) LINUX/windows下 socket 基于I/O复用的服务器端代码 解决多进程服务端创建进程资源浪费问题
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9613861.html 好了,继上一篇说到多进程服务端也是有缺点的,每创建一个进程就代表大量的运 ...
- windows下搭建学习objective-c 的运行环境【转载】
对于Iphone开发学习者而言,Object -c 是必修的语言.但是由于苹果的自我封闭的产业链发展模式(从芯片.机器.开发语言.终端产品.服务)的限制,要想开发针对苹果iPhone等产品的应用程序, ...
- windows下Socket链接溢出
最近在windows下使用通过多线程使用jdbc操作数据库,在线程数设置为5,并且每个线程执行完成后Sleep(1000),在这种情况下,竟然还会报错: java.net.SocketExceptio ...
- 使用Codeblock搭建Windows下Objec-c学习环境
学习Object-c如果使用的是Windows,一般推荐使用虚拟机,但是太重量级了,先要下载OS-X,又要下载x-code.这里推荐一种比较简便的方式,使用code-block来搭建简易的Object ...
- node.js在windows下的学习笔记(3)---npm
1.什么是npm npm是Node.js的包管理器,它允许开发人员在Node.js的应用程序中创建,共享,重用模块.之前我们通过node的官网的安装程序安装了Node.js,那么npm就已经装好了的. ...
- windows下socket编程:区分shutdown()及closesocket()
以下描述主要是针对windows平台下的TCP socket而言. 首先需要区分一下关闭socket和关闭TCP连接的区别,关闭TCP连接是指TCP协议层的东西,就是两个TCP端之间交换了一些协议包( ...
- windows下socket编程实现client和server双向通信
服务端代码server.c // server.cpp : Defines the entry point for the console application. // #include <s ...
- detours编译与windows下makefile学习
1.编译 windows环境命令行编译很少用,detours需要使用命令行编译,刚好试试,过程如下: 1.为了能够在所有目录中使用nmake命令,需要设置环境变量Path D:\Program Fil ...
- node.js在windows下的学习笔记(9)---文件I/O模块
开发中我们经常会有文件I/O的需求,node.js中提供一个名为fs的模块来支持I/O操作,fs模块的文件I/O是对标准POSIX函数的简单封装. 1.将"hello world" ...
随机推荐
- 《第一行代码》学习笔记——第1章 开始启程,你的第一行Android代码
1.3 创建你的第一个Android项目 1.3.1 创建HelloWorld项目 1.Application Name代表应用名称,手机上显示的就是它: 2.Project Name代表项目名称,其 ...
- 初学C++ 之 输入输出(IDE:vs2013)
#include <iostream> //引用头文件(输入输出) using namespace std; //引用命名空间,方便使用输入输出语句 class MathMethod { ...
- Fiddler (三) Composer创建和发送HTTP Request
之前已经写过两篇Fiddler的文章了,分别是[Fiddler教程] [Fiddler script用法]. 我准备把Fiddler写成一个系列. Fiddler的功能还有很多, 很多功能都没有 ...
- jstl标签2
我们前面讲的是ArrayList集合迭代,Hashmap/Hashset的情况下 举例: <h3>对map和set的迭代</h3> 放入字符串 <% //模拟 Map m ...
- 8种效果实例-jQuery anoSlide 焦点图轮播
anoslide是一款可调节效果至任意宽度大小,支持图文混合内容显示的图片轮播插件. 在线实例 单个 多个 动画延迟 自动播放 显示分页 显示标题 延迟加载 自适应高度 使用方法 <div cl ...
- Vanilla Masker – 功能强大的输入过滤插件
Vanilla Masker 是一个纯 JavaScript 实现的输入内容过滤和自动转换插件.现在你可以使用一个简单而纯粹的 JavaScript 库来控制你的 input 元素,而不需要加载 jQ ...
- Flexslider - 响应式的 jQuery 内容滚动插件
FlexSlider 是一款轻量的响应式 jQuery 内容滚动插件,能够帮助你在项目轻松的创建漂亮的内容滚动效果.这款插件曾经连续多年入选 WDL 的年度最佳 jQuery 插件,值得大家在网站开发 ...
- 高性能javascript学习笔记系列(1) -js的加载和执行
这篇笔记的内容主要涉及js的脚本位置,如何加载js脚本和脚本文件执行的问题,按照自己的理解结合高性能JavaScript整理出来的 javascript是解释性代码,解释性代码需要经历转化成计算机指令 ...
- js中如何获取纯正的undefined?
1.为什么要获取undefined? 因为undefined在javascript中不是保留字,可以被用户当做变量来赋值,这样如果我们后期需要用到undefined来检测一个变量的话,那么检测的值就不 ...
- linux系统免密码登陆
有两台机器,系统都是CentOS6.5,IP分别为192.168.2.150,192.168.2.151.现在150需要SSH免密码登陆151. 在150上面执行命令,当前登录用户是root: # s ...