关于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. Gym 101102J---Divisible Numbers(反推技巧题)

    题目链接 http://codeforces.com/gym/101102/problem/J Description standard input/output You are given an a ...

  2. contentResolver

    今天练习一个联系人的增,写,改,查的几项操作,其中一个重要的知识点  ContentResolver 还有一篇不错的参考文献 主要参见下面这个链接  http://cthhqu.blog.51cto. ...

  3. 添加项目到远程服务器(git)

    搞开发经常会用到把代码提交到远程服务器,之前也是懵懂的.今天来整理了一下.具体操作如下: 1.进入到远程服务器 ssh name -- 远程服务器地址 2.进入以后新建一个空的仓库 git init ...

  4. ssh: command not found的解决办法

    原来是没装ssh的客户端软件,晕死…… yum -y install openssh-clients

  5. java内存模型-总结

    处理器内存模型 顺序一致性内存模型是一个理论参考模型,JMM 和处理器内存模型在设计时通常会把顺序一致性内存模型作为参照.JMM 和处理器内存模型在设计时会对顺序一致性模型做一些放松,因为如果完全按照 ...

  6. java中newInstance()和new()

    在Java开发特别是数据库开发中,经常会用到Class.forName( )这个方法.通过查询Java Documentation我们会发现使用Class.forName( )静态方法的目的是为了动态 ...

  7. 15个最佳的代码评审(Code Review)工具

    代码评审可以被看作是计算机源代码的测试,它的目的是查找和修复引入到开发阶段的应用程序的错误,提高软件的整体素质和开发者的技能.代码审查程序以各种形式,如结对编程,代码抽查等.在这个列表中,我们编制了1 ...

  8. Autodesk Vault: 获取授权失败

    在登录Vault Explorer时弹出对话框,获取授权失败,不能登录. 1.首先Autodesk Vault Professional采用网络版授权方式,在安装之前之前你需要首先配置网络授权服务器, ...

  9. umeng track 相关

    NSString * appKey = @"57105bbbe0f55a7938002063"; NSString * deviceName = [[[UIDevice curre ...

  10. DropDownList 添加一个"请选择"或"全部"之类的项

    DropDownList在从数据库中得到数据源绑定后,添加一个"请选择"或"全部"之类的项 1:直接添加:<asp:ListItem Value=&quo ...