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" ...
随机推荐
- Gym 100917J---dir -C(RMQ--ST)
题目链接 http://codeforces.com/gym/100917/problem/D problem description Famous Berland coder and IT mana ...
- 阿里巴巴笔试整理系列 Session2 中级篇
1知识点储备-----2笔试题总结-----3面试经验总结 知识点储备 2014年8月29日在线笔试题:20单选(40分钟内完成)+附加题(2道编程+1道问答) 1. 通过算法生成的随机数是“伪随机” ...
- IO流(三)__字节流 标准输入输出流 转换流
一.字节流:FileInputStream 和FileOutputStream 基本操作和字符流类相同,没有flush,但是close还是要的 复制一个字节流文件 private static voi ...
- sql2012还原sql2008备份文件语句
--sql2012还原sql2008语句 --选择master数据库,新建查询 输入下面sql语句 --选择兼容模式(sql 2008)创建数据库db RESTORE DATABASE db FROM ...
- html和css的编码规范
HTML和CSS编码规范内容 一.HTML规范 二.CSS规范 三.注意事项: 四.常用的命名规则 五.CSS样式表文件命名 六.文件命名规则 一.HTML规范: 1.代码规范 页面的第一行添加标准模 ...
- C# yield
C#中的yield可以应用在一个可迭代的方法中,我们必须真正理解此关键词,才能将它正确的应用到实际生产中.为了说明yield会出现让我们迷惑的结果,下面先定义一个MyObject类: class My ...
- 分享50款 Android 移动应用程序图标【下篇】
在这个移动程序流行的时代,持续增长的应用程序经济充满了商业机遇.任何对应用程序设计感兴趣的人,将会喜欢上这里的50个独特的 Android 应用程序图标.这些例子中的图标能够让应用程序的设计更具吸引力 ...
- chrome developer tool—— 断点调试篇
断点,调试器的功能之一,可以让程序中断在需要的地方,从而方便其分析.也可以在一次调试中设置断点,下一次只需让程序自动运行到设置断点位置,便可在上次设置断点的位置中断下来,极大的方便了操作,同时节省了时 ...
- GRID方式ALV导出数据到本地丢掉最后一位的问题
这是SAP的一个Bug,FM方式ALV Grid和Class ALV Grid都会出现,但是ALV List好像没有这个BUG. 在以下几个条件满足的时候就会出现这个问题: 1.字段对应的域Con ...
- VSS 请求程序和 SharePoint 2013
Windows Server 中的 VSS 可用于创建可备份和还原 Microsoft SharePoint Foundation 的应用程序.VSS 提供了一个基础结构,使第三方存储管理程序.业务程 ...