关于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学习(一)的更多相关文章

  1. c++ 网络编程(四) LINUX/windows下 socket 基于I/O复用的服务器端代码 解决多进程服务端创建进程资源浪费问题

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9613861.html 好了,继上一篇说到多进程服务端也是有缺点的,每创建一个进程就代表大量的运 ...

  2. windows下搭建学习objective-c 的运行环境【转载】

    对于Iphone开发学习者而言,Object -c 是必修的语言.但是由于苹果的自我封闭的产业链发展模式(从芯片.机器.开发语言.终端产品.服务)的限制,要想开发针对苹果iPhone等产品的应用程序, ...

  3. windows下Socket链接溢出

    最近在windows下使用通过多线程使用jdbc操作数据库,在线程数设置为5,并且每个线程执行完成后Sleep(1000),在这种情况下,竟然还会报错: java.net.SocketExceptio ...

  4. 使用Codeblock搭建Windows下Objec-c学习环境

    学习Object-c如果使用的是Windows,一般推荐使用虚拟机,但是太重量级了,先要下载OS-X,又要下载x-code.这里推荐一种比较简便的方式,使用code-block来搭建简易的Object ...

  5. node.js在windows下的学习笔记(3)---npm

    1.什么是npm npm是Node.js的包管理器,它允许开发人员在Node.js的应用程序中创建,共享,重用模块.之前我们通过node的官网的安装程序安装了Node.js,那么npm就已经装好了的. ...

  6. windows下socket编程:区分shutdown()及closesocket()

    以下描述主要是针对windows平台下的TCP socket而言. 首先需要区分一下关闭socket和关闭TCP连接的区别,关闭TCP连接是指TCP协议层的东西,就是两个TCP端之间交换了一些协议包( ...

  7. windows下socket编程实现client和server双向通信

    服务端代码server.c // server.cpp : Defines the entry point for the console application. // #include <s ...

  8. detours编译与windows下makefile学习

    1.编译 windows环境命令行编译很少用,detours需要使用命令行编译,刚好试试,过程如下: 1.为了能够在所有目录中使用nmake命令,需要设置环境变量Path D:\Program Fil ...

  9. node.js在windows下的学习笔记(9)---文件I/O模块

    开发中我们经常会有文件I/O的需求,node.js中提供一个名为fs的模块来支持I/O操作,fs模块的文件I/O是对标准POSIX函数的简单封装. 1.将"hello world" ...

随机推荐

  1. R语言XML格式数据导入与处理

    数据解析 XML是一种可扩展标记语言,它被设计用来传输和存储数据.XML是各种应用程序之间进行数据传输的最常用的工具.它与Access,Oracle和SQL Server等数据库不同,数据库提供了更强 ...

  2. ASP.NET MVC下使用文件上传

    这里我通过使用uploadify组件来实现异步无刷新多文件上传功能. 1.首先下载组件包uploadify,我这里使用的版本是3.1 2.下载后解压,将组件包拷贝到MVC项目中 3.  根目录下添加新 ...

  3. Close与Dispose的区别

    Close与Dispose的区别: Close 是停业整顿,停业了,可以通过公关,再重开,物还是原来的物:只是关闭而已,没有释放真正的释放资源,可以重新打开:Close是关门Dispose是破产: D ...

  4. Numeral.js – 格式化和操作数字的 JavaScript 库

    Numeral.js 是一个用于格式化和操作数字的 JavaScript 库.数字可以格式化为货币,百分比,时间,甚至是小数,千位,和缩写格式,功能十分强大.支持包括中文在内的17种语言. 您可能感兴 ...

  5. javascript对象继承详解

    问题 比如我们有一个"动物"对象的构造函数. function animal() { this.type = '动物'; } 还有一个"猫"对象的构造函数. f ...

  6. 在 Xamarin.Android 中使用 Notification.Builder 构建通知

    0 背景 在 Android 4.0 以后,系统支持一种更先进的 Notification.Builder 类来发送通知.但 Xamarin 文档含糊其辞,多方搜索无果,遂决定自己摸索. 之前的代码: ...

  7. jQuery绑定事件的四种方式

      jQuery提供了多种绑定事件的方式,每种方式各有其特点,明白了它们之间的异同点,有助于我们在写代码的时候进行正确的选择,从而写出优雅而容易维护的代码.下面我们来看下jQuery中绑定事件的方式都 ...

  8. jQuery源码解读 - 数据缓存系统:jQuery.data

    jQuery在1.2后引入jQuery.data(数据缓存系统),主要的作用是让一组自定义的数据可以DOM元素相关联——浅显的说:就是让一个对象和一组数据一对一的关联. 一组和Element相关的数据 ...

  9. Android Property Animation动画

    3.0以前,android支持两种动画模式,tween animation,frame animation,在android3.0中又引入了一个新的动画系统:property animation,这三 ...

  10. Android NDK环境搭建及调用JNI的简单步骤

    转载请注明:http://www.cnblogs.com/tiantianbyconan/p/3396595.html Java Native Interface (JNI)标准是java平台的一部分 ...