Windows socket之最简单的socket程序
原文:Windows socket之最简单的socket程序
最简单的服务器的socket程序流程如下(面向连接的TCP连接 ):
1. WSAStartup(); 初始化网络库的使用。
2. socket(); 获得一个socket。
3. bind(); 把获得的socket绑定到一个ip 和端口。既然作为服务器, ip通常为本地IP127.0.0.1。
4. listen(); 监听已经绑定了指定端口的socket。
5. accept(); 接受一个来自客户端的连接。
accept()返回一个新的socket,该socket代表着本地服务器与某一个连接过来的客户端的链接。以该socket为参数,可以调用send函数往客户端发送数据,也可以调用recv函数接受客户端发送过来的函数。
最后服务器程序结束的时候调用closesocket()关闭socket, WSACleanup()终止网络库的使用,清理资源。
最简单的客户端的socket程序流程如下(同样是面向连接的TCP连接):
1. WSAStartup();初始化网络库的使用。
2. socket(); 获得一个socket。
3. connect(); 连接到一个 服务器。
连接成功后就可以收发数据了。收发完毕后调用closesocket()关闭socket,最后程序结束前调用 WSACleanup()清理资源。
下面直接上代码
需包含以下头文件和定义
#include <stdlib.h>
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#define SERVE_ADDRESS "127.0.0.1"
#define SERVE_PORT 7001
- // ---------------------------- WSAStartup() ----------------------------//
- WSADATA wsd;
- int resStartup = WSAStartup(MAKEWORD(2,2),&wsd);
- if(0 != resStartup)
- {
- printf("failed to WSAStartup!\n");
- goto Main_End;
- }
- //------------------------------------------------------------------------------//
- // ---------------------------- socket() ----------------------------//
- SOCKET serverSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- if(INVALID_SOCKET == serverSocket)
- {
- printf("failed to invoke socket, the socket returned is invalid!\n");
- goto Main_End;
- }
- // ------------------------------------------------------------------------------------//
- //---------------------------- bind() ----------------------------//
- // 初始化 struct sockaddr 结构体, SOCKADDR_IN就是 struct sockaddr的宏定义
- SOCKADDR_IN localAddr;
- localAddr.sin_family = AF_INET;
- localAddr.sin_addr.S_un.S_addr = inet_addr(SERVE_ADDRESS);
- localAddr.sin_port = htons(SERVE_PORT);
- memset(localAddr.sin_zero,0x0,sizeof(localAddr.sin_zero));
- //
- int resBind = bind(serverSocket,(sockaddr*)&localAddr,sizeof(SOCKADDR_IN));
- if(0 != resBind)
- {
- printf("failed to bind ! \n");
- goto Main_End;
- }
- //------------------------------------------------------------------------------------//
- //---------------------------- listen() ----------------------------//
- int resListen = listen(serverSocket,5);
- if(0 != resListen)
- {
- printf("failed to listen! \n");
- goto Main_End;
- }
- printf("the server is listening now!\n");
- //------------------------------------------------------------------------------------//
- //---------------------------- accept() ----------------------------//
- SOCKADDR_IN clientAddr;
- int addrLen = sizeof(clientAddr);
- SOCKET acceptedSocket = accept(serverSocket,(sockaddr*)&clientAddr,&addrLen);
- if(INVALID_SOCKET == acceptedSocket)
- {
- printf("accept error!\n");
- goto Main_End;
- }
- printf("a client has connected to the server!\n");
- //------------------------------------------------------------------------------------//
- char recvBuffer[256];
- char sendBuffer[256];
- strcpy(sendBuffer,"server:Welcome to connect !");
- int sendBufLen = strlen(sendBuffer);
- int resSend = send(acceptedSocket,sendBuffer,sendBufLen,0);
- while(true)
- {
- if(resSend != sendBufLen) //发送的长度与需要发送的长度不等
- {
- printf("send data error!!\n");
- break;
- }
- int recvLen = recv(acceptedSocket,recvBuffer,sizeof(recvBuffer),0);
- if(0 == recvLen)
- {
- printf("a client close the socket!\n");
- break;
- }
- else if(recvLen < 0)
- {
- printf("an error has happen when receiving\n");
- break;
- }
- recvBuffer[recvLen] = '\0';
- printf("client:%s\n",recvBuffer);
- //在客户发过来的数据前面加上server:再发回给客户端
- strcpy(sendBuffer,"server:");
- strcat(sendBuffer,recvBuffer);
- sendBufLen = strlen(sendBuffer);
- resSend = send(acceptedSocket,sendBuffer,sendBufLen,0);
- }
- closesocket(acceptedSocket);
- closesocket(serverSocket);
- Main_End:
- WSACleanup();
- system("pause");
- return 0;
客户端代码:
- //---------------------------- WSAStartup() ----------------------------//
- WSADATA wsd;
- int resStartup = WSAStartup(MAKEWORD(2,2),&wsd);
- if(0 != resStartup)
- {
- printf("failed to WSAStartup!\n");
- goto Main_End;
- }
- //------------------------------------------------------------------------------------//
- //---------------------------- socket() ----------------------------//
- SOCKET connSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- if(INVALID_SOCKET == connSocket)
- {
- printf("the socket returned is invalid!\n");
- goto Main_End;
- }
- //------------------------------------------------------------------------------------//
- //---------------------------- connect() ----------------------------//
- //初始化struct sockaddr 结构体
- SOCKADDR_IN serverAddr;
- serverAddr.sin_family = AF_INET;
- serverAddr.sin_addr.S_un.S_addr = inet_addr(SERVE_ADDRESS);
- serverAddr.sin_port = htons(SERVE_PORT);
- memset(serverAddr.sin_zero,0x0,sizeof(serverAddr.sin_zero));
- //connect
- int resConn = connect(connSocket,(sockaddr*)&serverAddr,sizeof(serverAddr));
- if(0 != resConn)
- {
- printf("failed to connect to server!!\n");
- goto Main_End;
- }
- //------------------------------------------------------------------------------------//
- char sendBuffer[256];
- char recvBuffer[256];
- while(true)
- {
- int recvLen = recv(connSocket,recvBuffer,256,0);
- if(recvLen < 0)
- {
- printf("receive error!!\n");
- break;
- }
- else if(0 == recvLen)
- {
- printf("the server close the socket!\n");
- }
- recvBuffer[recvLen] = '\0';
- printf("the data recv:%s\n\n\n",recvBuffer);
- printf("please input what you want to send:\n");
- gets(sendBuffer);
- if(0 == strcmp(sendBuffer,"exit"))
- {
- break;
- }
- int sendDataLen = strlen(sendBuffer);
- int nDataSent = send(connSocket,sendBuffer,sendDataLen,0);
- if(nDataSent != sendDataLen)
- {
- printf("failed to send data!!\n");
- break;
- }
- }
- closesocket(connSocket);
- printf("the connection is closed!\n");
- Main_End:
- WSACleanup();
- system("pause");
- return 0;
客户端连接到服务端后,每次给服务端发送一段内容,服务器在内容前面加上server:再发送给客户端。
当客户端发送的内容是exit时,客户端程序跳出循环,关闭socket断开连接。服务端发现客户端断开连接后也关闭套接字结束程序。
当然上面程序只为了演示最简单的网络编程。有若干漏洞。
1. 服务器只能接受一个客户端连接。当然加一个循环语句进去可以重复地接受客户端的连接,但是仍然是每次只处理一个客户端连接。
2.accept, connect,send,recv函数默认均是阻塞函数。当没有客户连接到服务端时,服务端阻塞在accept函数,无法退出程序。当服务器在接受客户端的数据时,如果客户端不发送数据,也不断开连接,那么服务端阻塞在recv函数,无法退出程序。
改进该程序,使得服务端随时都可以停止服务退出程序,无论有多少个用户已经在连接。
为了多个客户端可以同时连接,最容易理解的便是利用多线程。每一个连接的客户端都用一个线程去处理它的通信。
至于为了随时可以退出服务端,不能再调用永久阻塞的函数了。利用select函数,可以阻塞指定的时间,阻塞期间不占CPU。
int select( __in int nfds, __in_out fd_set*readfds, __in_out fd_set*writefds, __in_out fd_set*exceptfds,
__in const struct timeval*timeout);
- nfds
-
用于兼容Berkeley sockets.不用理会,随便给个0值就OK。
- readfds
-
用于检查是否存在可读socket的的一个socket集合。可为空。
- writefds
-
用于检查是否存在可写socket的一个socket集合。可为空。
- exceptfds
-
用于检查是否存在有错误的socket的一个 socket集合,可为空。
- timeout
-
TIMEVAL结构体,用于指定该函数阻塞多长时间。
在 调用select时,当readfds不为空时,当readfds中任何一个socket就绪可读时,或者当writefds不为空且writefds中任何一个socket准备就绪可写,或者当exceptfds不为空且任何一个socket发生socket错误时,select就立即返回。否则,直到timeout指定的时间过去以后才返回。
返回值,返回准备就绪的socket的个数。如果为0,说明该函数超时了,如果大于0,说明至少有一个socket就绪。如果小于0,说明发生错误了。
fd_set 是一种集合类型。
typedef struct fd_set {
u_int fd_count; /* how many are SET? */
SOCKET fd_array[FD_SETSIZE]; /* an array of SOCKETs */
} fd_set;
记录着一个socket数组,以及里面的socket个数。
struct timeval是一个表示等待时间的结构体。
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
};
tv_sec表示有多少秒,tv_usec表示有多少毫秒。
对于fd_set类型,用到几个宏定义函数。
FD_ZERO(fd_set*), 清空fd_set集合
FD_SET(SOCKET,fd_set*),把socket加入fd_set集合。
FD_ISSET(SOCKET,fd_set*),判断socket是否在集合fd_set中,并且socket准备就绪。
FD_CLR(SOCKET,fd_set*),如果fd_set存在该SOCKET,则移除它。
下面是改进后的服务端代码
- typedef struct _ThreadInfo
- {
- HANDLE hThread;
- bool bRunning;
- SOCKET sock;
- }ThreadInfo;
- typedef struct _AcceptThreadParam
- {
- bool bRunning;
- SOCKET listeningSocket;
- }AcceptThreadParam;
- std::list<ThreadInfo*> g_threadInfoList;
- CRITICAL_SECTION g_csForList;
- DWORD WINAPI ListeningThread(LPVOID lpParameter);
- DWORD WINAPI CommunicationThread(LPVOID lpParameter);
- int _tmain(int argc, _TCHAR* argv[])
- {
- _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
- // ---------------------------- WSAStartup() ----------------------------//
- WSADATA wsd;
- int resStartup = WSAStartup(MAKEWORD(2,2),&wsd);
- if(0 != resStartup)
- {
- printf("failed to WSAStartup!\n");
- return -1;
- }
- //------------------------------------------------------------------------------//
- InitializeCriticalSection(&g_csForList);
- // ---------------------------- socket() ----------------------------//
- SOCKET serverSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- if(INVALID_SOCKET == serverSocket)
- {
- printf("failed to invoke socket, the socket returned is invalid!\n");
- goto Main_End;
- }
- // ------------------------------------------------------------------------------------//
- //---------------------------- bind() ----------------------------//
- // 初始化 struct sockaddr 结构体, SOCKADDR_IN就是 struct sockaddr的宏定义
- SOCKADDR_IN localAddr;
- localAddr.sin_family = AF_INET;
- localAddr.sin_addr.S_un.S_addr = inet_addr(SERVE_ADDRESS);
- localAddr.sin_port = htons(SERVE_PORT);
- memset(localAddr.sin_zero,0x0,sizeof(localAddr.sin_zero));
- //
- int resBind = bind(serverSocket,(sockaddr*)&localAddr,sizeof(SOCKADDR_IN));
- if(0 != resBind)
- {
- printf("failed to bind ! \n");
- goto Main_End;
- }
- //------------------------------------------------------------------------------------//
- //---------------------------- listen() ----------------------------//
- int resListen = listen(serverSocket,5);
- if(0 != resListen)
- {
- printf("failed to listen! \n");
- goto Main_End;
- }
- //------------------------------------------------------------------------------------//
- AcceptThreadParam threadParam;
- threadParam.bRunning = true;
- threadParam.listeningSocket = serverSocket;
- HANDLE hListeningThread = CreateThread(0,0,ListeningThread,&threadParam,0,0);
- if(0 == hListeningThread)
- {
- printf("failed to create the listening thread!\n");
- goto Main_End;
- }
- else
- {
- printf("the server is listening now!pass any key to close the server!\n");
- }
- while(true)
- {
- char ch = getchar();
- threadParam.bRunning = false;
- DWORD resWait = WaitForSingleObject(hListeningThread,3000);
- if(WAIT_TIMEOUT == resWait)
- {
- printf("failed to wait for the listening thread exiting!\n");
- }
- else
- {
- printf("the listening thread has exited!\n");
- }
- break;
- }
- Main_End:
- if(INVALID_SOCKET != serverSocket)
- {
- closesocket(serverSocket);
- serverSocket = INVALID_SOCKET;
- }
- WSACleanup();
- DeleteCriticalSection(&g_csForList);
- system("pause");
- return 0;
- }
- DWORD WINAPI ListeningThread(LPVOID lpParameter)
- {
- AcceptThreadParam* pAcceptThreadParam = (AcceptThreadParam*)lpParameter;
- SOCKET serverSocket = pAcceptThreadParam->listeningSocket;
- while(pAcceptThreadParam->bRunning)
- {
- //---------------------------- accept() ----------------------------//
- fd_set fdAccept;
- FD_ZERO(&fdAccept);
- FD_SET(serverSocket,&fdAccept);
- TIMEVAL acceptTimeVal;
- acceptTimeVal.tv_sec = 1;
- acceptTimeVal.tv_usec = 0;
- int selRes = select(0,&fdAccept,0,0,&acceptTimeVal);
- if(selRes > 0)
- {
- SOCKADDR_IN clientAddr;
- int addrLen = sizeof(clientAddr);
- SOCKET acceptedSocket = accept(serverSocket,(sockaddr*)&clientAddr,&addrLen);
- if(INVALID_SOCKET == acceptedSocket)
- {
- printf("accept error!\n");
- break;
- }
- printf("a client has connected to the server!\n");
- ThreadInfo* pTI = new ThreadInfo;
- pTI->bRunning = true;
- pTI->sock = acceptedSocket;
- pTI->hThread = CreateThread(0,0,CommunicationThread,(LPVOID)pTI,0,0);
- if(0 == pTI->hThread)
- {
- printf("failed to create a thread!\n");
- delete pTI;
- pTI = 0;
- }
- else
- {
- EnterCriticalSection(&g_csForList);
- g_threadInfoList.push_back(pTI);
- LeaveCriticalSection(&g_csForList);
- }
- }
- else if(selRes < 0)
- {
- printf("an error has occured when listening !\n");
- break;
- }
- }
- std::list<ThreadInfo*> tempList;
- EnterCriticalSection(&g_csForList);
- std::list<ThreadInfo*>::iterator listIter;
- for(listIter = g_threadInfoList.begin(); listIter != g_threadInfoList.end(); listIter++)
- {
- (*listIter)->bRunning = false;
- tempList.push_back(*listIter);
- }
- g_threadInfoList.clear();
- LeaveCriticalSection(&g_csForList);
- int nSuccessfullyExit = 0;
- for(listIter = tempList.begin(); listIter != tempList.end(); listIter++)
- {
- DWORD resWait = WaitForSingleObject((*listIter)->hThread,2000);
- if(WAIT_TIMEOUT == resWait)
- {
- printf("failed to wait for a communication thread exiting!\n");
- }
- else
- {
- nSuccessfullyExit++;
- }
- delete (*listIter);
- }
- printf("succeed waiting for %d thread exiting!\n",nSuccessfullyExit);
- tempList.clear();
- printf("listening thread is exiting!\n");
- return 0;
- }
- DWORD WINAPI CommunicationThread(LPVOID lpParameter)
- {
- ThreadInfo* pThreadInfo = (ThreadInfo*)lpParameter;
- SOCKET clientSocket = pThreadInfo->sock;
- fd_set fdRead,fdWrite;
- FD_ZERO(&fdRead);
- FD_ZERO(&fdWrite);
- FD_SET(clientSocket,&fdRead);
- FD_SET(clientSocket,&fdWrite);
- TIMEVAL sendTimeVal;
- sendTimeVal.tv_sec = 0;
- sendTimeVal.tv_usec = 500;
- int selRes = select(0,0,&fdWrite,0,&sendTimeVal);
- if(selRes <= 0)
- {
- goto ThreadOver;
- }
- char recvBuffer[256];
- char sendBuffer[256];
- strcpy(sendBuffer,"server:Welcome to connect !");
- int sendBufLen = strlen(sendBuffer);
- int resSend = send(clientSocket,sendBuffer,sendBufLen,0);
- if(resSend != sendBufLen)
- {
- printf("there are %d bytes to send, but it just succeeded sending %d bytes!\n",sendBufLen,resSend);
- goto ThreadOver;
- }
- while(pThreadInfo->bRunning)
- {
- FD_ZERO(&fdRead);
- FD_SET(pThreadInfo->sock,&fdRead);
- TIMEVAL recvTimeVal;
- recvTimeVal.tv_sec = 0;
- recvTimeVal.tv_usec = 500;
- int recvSelRes = select(0,&fdRead,0,0,&recvTimeVal);
- if(recvSelRes < 0)
- {
- printf("socket error when receiving!\n");
- break;
- }
- else if(recvSelRes > 0)
- {
- int recvLen = recv(clientSocket,recvBuffer,sizeof(recvBuffer),0);
- if(0 == recvLen)
- {
- printf("a client close the socket!\n");
- break;
- }
- else if(recvLen < 0)
- {
- printf("an error has happen when recving\n");
- break;
- }
- else
- {
- recvBuffer[recvLen] = '\0';
- printf("a client:%s\n",recvBuffer);
- strcpy(sendBuffer,"server:");
- strcat(sendBuffer,recvBuffer);
- sendBufLen = strlen(sendBuffer);
- FD_ZERO(&fdWrite);
- FD_SET(pThreadInfo->sock,&fdWrite);
- sendTimeVal.tv_sec = 0;
- sendTimeVal.tv_usec = 500;
- int sendSelRes = select(0,0,&fdWrite,0,&sendTimeVal);
- if(sendSelRes > 0)
- {
- int bytesSent = send(clientSocket,sendBuffer,sendBufLen,0);
- if(bytesSent != sendBufLen)
- {
- printf("there are %d bytes to be sent,but only %d bytes are sent!\n",sendBufLen,bytesSent);
- break;
- }
- }
- else
- {
- printf("failed to send in 500 ms!\n");
- break;
- }
- }
- }
- }
- ThreadOver:
- closesocket(pThreadInfo->sock);
- bool bMainThreadWaiting = true;
- EnterCriticalSection(&g_csForList);
- std::list<ThreadInfo*>::iterator listIter;
- for(listIter = g_threadInfoList.begin(); listIter != g_threadInfoList.end(); listIter++)
- {
- if(pThreadInfo == (*listIter))
- {
- bMainThreadWaiting = false;
- g_threadInfoList.erase(listIter);
- break;
- }
- }
- LeaveCriticalSection(&g_csForList);
- if(false == bMainThreadWaiting)
- {
- CloseHandle(pThreadInfo->hThread);
- delete pThreadInfo;
- pThreadInfo = 0;
- }
- return 0;
- }
前面的代码与之前的一样,改变的地方在于accept的地方。对于一个监听的socket,如果该socket可读,说明有用户连接过来了。
全局维护了一个纪录创建的线程的信息的链表,每创建一个线程都有一个标识该线程是否应该继续循环执行的bool变量。当bRunning变为false的时候,线程函数跳出循环,返回。
当需要停止服务端运行时,服务端只需要按任何一个键和回车,就会通知线程退出,并且调用WaitForSingleObject(),来确认线程已退出。还有利用了 EnterCriticalSection()和LeaveCriticalSection()临界区函数来保证只有一个线程在操作全局的链表。
使用多线程要消耗一定的资源。对于fd_set,默认最多可以容纳64个socket.所以可以用1个线程去处理64个客户端的连接。而不必每个客户端都创建一个线程。
代码如下:
- typedef struct _AcceptThreadParam
- {
- bool bRunning;
- SOCKET listeningSocket;
- }AcceptThreadParam;
- #define SOCKET_ARRAY_SIZE 64
- SOCKET g_socketArray[SOCKET_ARRAY_SIZE];
- int g_socketCount = 0;
- CRITICAL_SECTION g_csForSocketArray;
- DWORD WINAPI ListeningThread(LPVOID lpParameter);
- DWORD WINAPI CommunicationThread(LPVOID lpParameter);
- int _tmain(int argc, _TCHAR* argv[])
- {
- _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
- // ---------------------------- WSAStartup() ----------------------------//
- WSADATA wsd;
- int resStartup = WSAStartup(MAKEWORD(2,2),&wsd);
- if(0 != resStartup)
- {
- printf("failed to WSAStartup!\n");
- return -1;
- }
- //------------------------------------------------------------------------------//
- InitializeCriticalSection(&g_csForSocketArray);
- g_socketCount = 0;
- // ---------------------------- socket() ----------------------------//
- SOCKET serverSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- if(INVALID_SOCKET == serverSocket)
- {
- printf("failed to invoke socket, the socket returned is invalid!\n");
- goto Main_End;
- }
- // ------------------------------------------------------------------------------------//
- //---------------------------- bind() ----------------------------//
- // 初始化 struct sockaddr 结构体, SOCKADDR_IN就是 struct sockaddr的宏定义
- SOCKADDR_IN localAddr;
- localAddr.sin_family = AF_INET;
- localAddr.sin_addr.S_un.S_addr = inet_addr(SERVE_ADDRESS);
- localAddr.sin_port = htons(SERVE_PORT);
- memset(localAddr.sin_zero,0x0,sizeof(localAddr.sin_zero));
- //
- int resBind = bind(serverSocket,(sockaddr*)&localAddr,sizeof(SOCKADDR_IN));
- if(0 != resBind)
- {
- printf("failed to bind ! \n");
- goto Main_End;
- }
- //------------------------------------------------------------------------------------//
- //---------------------------- listen() ----------------------------//
- int resListen = listen(serverSocket,5);
- if(0 != resListen)
- {
- printf("failed to listen! \n");
- goto Main_End;
- }
- //------------------------------------------------------------------------------------//
- AcceptThreadParam threadParam;
- threadParam.bRunning = true;
- threadParam.listeningSocket = serverSocket;
- bool bCommunicationThreadRunning = true;
- HANDLE hListeningThread = CreateThread(0,0,ListeningThread,&threadParam,0,0);
- HANDLE hCommunicationThread = CreateThread(0,0,CommunicationThread,&bCommunicationThreadRunning,0,0);
- if(0 == hListeningThread || 0 == hCommunicationThread)
- {
- printf("failed to create a thread!\n");
- if(0 != hListeningThread)
- {
- threadParam.bRunning = false;
- WaitForSingleObject(hListeningThread,2000);
- CloseHandle(hListeningThread);
- }
- if(0 != hCommunicationThread)
- {
- bCommunicationThreadRunning = false;
- WaitForSingleObject(hCommunicationThread,2000);
- CloseHandle(hCommunicationThread);
- }
- goto Main_End;
- }
- else
- {
- printf("the server is listening now!pass any key to close the server!\n");
- }
- while(true)
- {
- char ch = getchar();
- threadParam.bRunning = false;
- bCommunicationThreadRunning = false;
- DWORD resWait = WaitForSingleObject(hListeningThread,3000);
- if(WAIT_TIMEOUT == resWait)
- {
- printf("failed to wait for the listening thread exiting!\n");
- }
- else
- {
- printf("the listening thread has exited!\n");
- }
- CloseHandle(hListeningThread);
- resWait = WaitForSingleObject(hCommunicationThread,3000);
- if(WAIT_TIMEOUT == resWait)
- {
- printf("failed to wait for the communication thread exiting!\n");
- }
- else
- {
- printf("the communication thread has exited!\n");
- }
- CloseHandle(hCommunicationThread);
- break;
- }
- Main_End:
- if(INVALID_SOCKET != serverSocket)
- {
- closesocket(serverSocket);
- serverSocket = INVALID_SOCKET;
- }
- WSACleanup();
- DeleteCriticalSection(&g_csForSocketArray);
- system("pause");
- return 0;
- }
- DWORD WINAPI ListeningThread(LPVOID lpParameter)
- {
- AcceptThreadParam* pAcceptThreadParam = (AcceptThreadParam*)lpParameter;
- SOCKET serverSocket = pAcceptThreadParam->listeningSocket;
- while(pAcceptThreadParam->bRunning)
- {
- //---------------------------- accept() ----------------------------//
- fd_set fdAccept;
- FD_ZERO(&fdAccept);
- FD_SET(serverSocket,&fdAccept);
- TIMEVAL acceptTimeVal;
- acceptTimeVal.tv_sec = 1;
- acceptTimeVal.tv_usec = 0;
- int selRes = select(0,&fdAccept,0,0,&acceptTimeVal);
- if(selRes > 0)
- {
- SOCKADDR_IN clientAddr;
- int addrLen = sizeof(clientAddr);
- SOCKET acceptedSocket = accept(serverSocket,(sockaddr*)&clientAddr,&addrLen);
- if(INVALID_SOCKET == acceptedSocket)
- {
- printf("accept error!\n");
- break;
- }
- printf("a client has connected to the server!\n");
- fd_set fdWrite;
- FD_ZERO(&fdWrite);
- FD_SET(acceptedSocket,&fdWrite);
- TIMEVAL writeTimeVal;
- writeTimeVal.tv_sec = 0;
- writeTimeVal.tv_usec = 500;
- int writeSelRes = select(0,0,&fdWrite,0,&writeTimeVal);
- if(writeSelRes > 0)
- {
- int sendBufferLen = strlen("server:Welcome to connect!");
- int bytesSent = send(acceptedSocket,"server:Welcome to connect!",sendBufferLen,0);
- if(bytesSent == sendBufferLen)
- {
- EnterCriticalSection(&g_csForSocketArray);
- if(g_socketCount < 64)
- {
- g_socketArray[g_socketCount] = acceptedSocket;
- g_socketCount++;
- }
- else
- {
- printf("the server has accepted more than 64 clients!\n");
- closesocket(acceptedSocket);
- }
- LeaveCriticalSection(&g_csForSocketArray);
- }
- else
- {
- printf("send error, there are %d bytes to be sent, but only %d bytes are sent!\n",sendBufferLen,bytesSent);
- closesocket(acceptedSocket);
- }
- }
- else
- {
- printf("select error of can not wait for sending data when select!\n");
- closesocket(acceptedSocket);
- }
- }
- else if(selRes < 0)
- {
- printf("an error has occured when listening !\n");
- break;
- }
- }
- printf("listening thread is exiting!\n");
- return 0;
- }
- DWORD WINAPI CommunicationThread(LPVOID lpParameter)
- {
- bool* pBRunning = (bool*)lpParameter;
- char recvBuffer[256];
- char tempBuffer[256];
- while(true == *pBRunning)
- {
- int currentSocketCount = 0;
- EnterCriticalSection(&g_csForSocketArray);
- if(0 == g_socketCount)
- {
- LeaveCriticalSection(&g_csForSocketArray);
- Sleep(200);
- continue;
- }
- currentSocketCount = g_socketCount;
- LeaveCriticalSection(&g_csForSocketArray);
- fd_set fdRead;
- FD_ZERO(&fdRead);
- for(int i = 0; i < currentSocketCount; i++)
- {
- FD_SET(g_socketArray[i],&fdRead);
- }
- TIMEVAL readTimeVal;
- readTimeVal.tv_sec = 1;
- readTimeVal.tv_usec = 0;
- int selRes = select(0,&fdRead,0,0,&readTimeVal);
- if(selRes > 0)
- {
- for(int i = 0; i < currentSocketCount; i++)
- {
- if(FD_ISSET(g_socketArray[i],&fdRead) != 0)
- {
- int bytesRecv = recv(g_socketArray[i],recvBuffer,sizeof(recvBuffer),0);
- if(bytesRecv > 0)
- {
- recvBuffer[bytesRecv] = '\0';
- printf("the %d client: %s\n",i + 1,recvBuffer);
- sprintf(tempBuffer,"the server:%s",recvBuffer);
- fd_set fdWrite;
- FD_ZERO(&fdWrite);
- FD_SET(g_socketArray[i],&fdWrite);
- TIMEVAL writeTimeVal;
- writeTimeVal.tv_sec = 0;
- writeTimeVal.tv_usec = 500;
- int writeSelRes = select(g_socketArray[i],0,&fdWrite,0,&writeTimeVal);
- if(writeSelRes > 0)
- {
- int sendBufLen = strlen(tempBuffer);
- int bytesSent = send(g_socketArray[i],tempBuffer,sendBufLen,0);
- if(bytesSent == sendBufLen)
- {
- break;
- }
- else
- {
- printf("there are %d bytes to be sent,but only %d bytes are sent!\n",sendBufLen,bytesSent);
- }
- }
- else
- {
- printf("select error!\n");
- }
- }
- else if(0 == bytesRecv)
- {
- printf("the %d client has closed the socket!\n",i + 1);
- }
- else
- {
- printf("recv error!\n");
- }
- closesocket(g_socketArray[i]);
- EnterCriticalSection(&g_csForSocketArray);
- g_socketArray[i] = g_socketArray[g_socketCount - 1];
- g_socketCount--;
- LeaveCriticalSection(&g_csForSocketArray);
- }
- }
- }
- else if(selRes < 0)
- {
- printf("select error in communication thread!\n");
- }
- }
- EnterCriticalSection(&g_csForSocketArray);
- for(int i = 0; i < g_socketCount; i++)
- {
- closesocket(g_socketArray[i]);
- }
- LeaveCriticalSection(&g_csForSocketArray);
- printf("the communication thread is exiting!\n");
- return 0;
- }
完成的功能一样。只需要一个线程就可以处理多个客户端了。
还可以用异步IO来实现该服务器,以下是用完成端口来实现同样功能的服务器。
- typedef struct _RepeatAcceptingThreadParam
- {
- SOCKET listeningSocket;
- bool* pBRunning;
- }RepeatAcceptingThreadParam;
- typedef struct _CompletionPortWorkerThreadParam
- {
- HANDLE hCompletionPort;
- bool* pBRunning;
- }CompletionPortWorkerThreadParam;
- #define MESSAGE_BUF_SIZE 1024
- enum OPERATION_TYPE
- {
- OPERATION_SEND,
- OPERATION_RECV
- };
- typedef struct
- {
- SOCKET sock;
- WSAOVERLAPPED overlap;
- WSABUF wsaBuf;
- char message[1024];
- DWORD bytesRecv;
- DWORD flags;
- OPERATION_TYPE operationType;
- }PER_IO_OPERATION_DATA;
- //global vector, which saves the information of the client sockets connected to the server
- std::vector<PER_IO_OPERATION_DATA*> g_perIoDataPointerVec;
- //accept sockets connected to the server's listening socket in a recycle - while
- DWORD WINAPI RepeatAcceptingThread(LPVOID lpParameter);
- //the worker thread that deal with the communications between the server and the clients.
- DWORD WINAPI CompletionPortWorkerThread(LPVOID lpParameter);
- int _tmain(int argc,_TCHAR* argv[])
- {
- _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
- // ---------------------------- WSAStartup() ----------------------------//
- WSADATA wsd;
- int resStartup = WSAStartup(MAKEWORD(2,2),&wsd);
- if(0 != resStartup)
- {
- printf("failed to WSAStartup!\n");
- return -1;
- }
- //------------------------------------------------------------------------------//
- // ---------------------------- socket() ----------------------------//
- SOCKET serverSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- if(INVALID_SOCKET == serverSocket)
- {
- printf("failed to invoke socket, the socket returned is invalid!\n");
- return -1;
- }
- // ------------------------------------------------------------------------------------//
- //---------------------------- bind() ----------------------------//
- // 初始化 struct sockaddr 结构体, SOCKADDR_IN就是 struct sockaddr的宏定义
- SOCKADDR_IN localAddr;
- localAddr.sin_family = AF_INET;
- localAddr.sin_addr.S_un.S_addr = inet_addr(SERVE_ADDRESS);
- localAddr.sin_port = htons(SERVE_PORT);
- memset(localAddr.sin_zero,0x0,sizeof(localAddr.sin_zero));
- //
- int resBind = bind(serverSocket,(sockaddr*)&localAddr,sizeof(SOCKADDR_IN));
- if(0 != resBind)
- {
- printf("failed to bind ! \n");
- closesocket(serverSocket);
- return -1;
- }
- //------------------------------------------------------------------------------------//
- //---------------------------- listen() ----------------------------//
- int resListen = listen(serverSocket,5);
- if(0 != resListen)
- {
- printf("failed to listen! \n");
- closesocket(serverSocket);
- return -1;
- }
- //------------------------------------------------------------------------------------//
- bool bRepeatAcceptingThreadRunning = true; // a bool variable that take control of terminating the RepeatAcceptingThread.
- //init the parameter for the RepeatAcceptingThread.
- RepeatAcceptingThreadParam rtp;
- rtp.listeningSocket = serverSocket;
- rtp.pBRunning = &bRepeatAcceptingThreadRunning;
- HANDLE hRepeatAcceptingThread = CreateThread(0,0,RepeatAcceptingThread,&rtp,0,0);
- if(0 == hRepeatAcceptingThread)
- {
- printf("failed to create the repeat-accepting thread!\n");
- closesocket(serverSocket);
- return -1;
- }
- printf("the repeat-accepting thread has run!\n");
- while(true)
- {
- // pass any key
- char ch = getchar();
- bRepeatAcceptingThreadRunning = false;//to notify the RepeatAcceptingThread to exit safely
- DWORD waitRes = WaitForSingleObject(hRepeatAcceptingThread,3000);
- if(WAIT_TIMEOUT == waitRes)
- {
- printf("failed to wait for the repeatAcceptingThread exiting!\n");
- }
- else
- {
- printf("the repeat accepting thread has exited!\n");
- }
- CloseHandle(hRepeatAcceptingThread);
- break;
- }
- system("pause");
- return 0;
- }
- DWORD WINAPI RepeatAcceptingThread(LPVOID lpParameter)
- {
- //get the parameters passed by the creator of the thread.
- RepeatAcceptingThreadParam* pParam = (RepeatAcceptingThreadParam*)lpParameter;
- SOCKET listeningSocket = pParam->listeningSocket;
- bool* pStillRun = pParam->pBRunning;
- // create a completion port
- HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
- if(0 == hCompletionPort)
- {
- printf("failed to CreateIoCompletionPort!\n");
- return -1;
- }
- // a bool variable for notifying the worker threads of exiting.
- bool bWorkThreadRunning = true;
- // a vector of HANDLEs,which will be used for synchronization of waiting the worker threads to exit.
- std::vector<HANDLE> threadHandlesVec;
- SYSTEM_INFO systemInfo;
- GetSystemInfo(&systemInfo);
- //the parameter to be passed to the worker thread.
- CompletionPortWorkerThreadParam cpwtp;
- cpwtp.pBRunning = &bWorkThreadRunning;
- cpwtp.hCompletionPort = hCompletionPort;
- for(int i = 0; i < systemInfo.dwNumberOfProcessors; i++)
- {
- HANDLE hThread = CreateThread(0,0,CompletionPortWorkerThread,&cpwtp,0,0);
- if(0 == hThread)
- {
- printf("failed to create a completion port worker thread!\n");
- bWorkThreadRunning = false;
- // terminate all threads created safely.
- std::vector<HANDLE>::iterator vecIter;
- for(vecIter = threadHandlesVec.begin(); vecIter != threadHandlesVec.end(); vecIter++)
- {
- DWORD waitRes = WaitForSingleObject(*vecIter,2000);
- if(WAIT_TIMEOUT == waitRes)
- {
- printf("failed the wait for the completion port worker thread!\n");
- }
- CloseHandle(*vecIter);
- }
- threadHandlesVec.clear();
- CloseHandle(hCompletionPort);
- return -1;
- }
- else
- {
- threadHandlesVec.push_back(hThread); //add the handle to the vector
- }
- }
- printf("succeed creating completion port worker threads!\n");
- while(true == *pStillRun)
- {
- fd_set fdAccept;
- FD_ZERO(&fdAccept);
- FD_SET(listeningSocket,&fdAccept);
- TIMEVAL acceptTimeVal;
- acceptTimeVal.tv_sec = 1;
- acceptTimeVal.tv_usec = 0;
- int selRes = select(0,&fdAccept,0,0,&acceptTimeVal);
- if(selRes > 0) // a client connected
- {
- SOCKADDR_IN clientAddr;
- int addrLen = sizeof(clientAddr);
- SOCKET acceptedSocket = WSAAccept(listeningSocket,(struct sockaddr*)&clientAddr,&addrLen,0,0);
- if(0 == acceptedSocket)
- {
- printf("failed to accept a connection!\n");
- }
- else
- {
- printf("a clent %s:%d has connected!\n",inet_ntoa(clientAddr.sin_addr),ntohs(clientAddr.sin_port));
- PER_IO_OPERATION_DATA* perIoData = new PER_IO_OPERATION_DATA;
- if(0 == perIoData)
- {
- closesocket(acceptedSocket);
- printf("failed to new a struct! there is not enough memory!\n\n");
- }
- else
- {
- //associate the newly connected client socket with the completion port.
- if(0 == CreateIoCompletionPort((HANDLE)acceptedSocket,hCompletionPort,(ULONG_PTR)perIoData,0))
- {
- printf("failed to associate the newly connected client socket with the completion port!\n");
- closesocket(acceptedSocket);
- delete perIoData;
- perIoData = 0;
- }
- else
- {
- //associated successfully, Set the information of the client socket in A PER_IO_OPERATION_DATA struct.
- //when a IO operation is completed, we can get notified with the struct to be one of the parameters.
- perIoData->sock = acceptedSocket;
- perIoData->operationType = OPERATION_SEND;
- perIoData->wsaBuf.buf = perIoData->message;
- perIoData->overlap.hEvent = INVALID_HANDLE_VALUE;
- strcpy(perIoData->message,"Welcome to connect to the server!");
- perIoData->wsaBuf.len = strlen(perIoData->message);
- int sendRes = WSASend(acceptedSocket,&(perIoData->wsaBuf),1,&(perIoData->bytesRecv),0,0,0);
- if(0 == sendRes) //finished immediately
- {
- // asynchronously invoke a receive operation. When the reception finished,we can get its information by
- // invoking GetQueuedCompletionStatus()
- perIoData->wsaBuf.buf = perIoData->message;
- perIoData->wsaBuf.len = MESSAGE_BUF_SIZE;
- perIoData->flags = 0;
- perIoData->operationType = OPERATION_RECV;
- ZeroMemory(&perIoData->overlap,sizeof(perIoData->overlap));
- int recvRes = WSARecv(acceptedSocket,&perIoData->wsaBuf,1,&perIoData->bytesRecv,&perIoData->flags,&perIoData->overlap,0);
- if(0 == recvRes) //the receiving operation finished immediately , the information of the operation has been queued.
- {
- g_perIoDataPointerVec.push_back(perIoData);
- }
- else if(SOCKET_ERROR == recvRes && WSA_IO_PENDING == WSAGetLastError()) //the receiving operation will finish later
- {
- g_perIoDataPointerVec.push_back(perIoData);
- }
- else
- {
- printf("failed to WSARecv!\n");
- closesocket(acceptedSocket);
- delete perIoData;
- perIoData = 0;
- }
- }
- else if(SOCKET_ERROR == sendRes && WSA_IO_PENDING == WSAGetLastError()) //the sending operation will finish later
- {
- g_perIoDataPointerVec.push_back(perIoData);
- }
- else
- {
- //int lastErr = WSAGetLastError();
- printf("send data error!\n");
- closesocket(acceptedSocket);
- delete perIoData;
- perIoData = 0;
- }
- }
- }
- }
- }
- else if(selRes < 0)
- {
- printf("select error!\n");
- }
- }
- bWorkThreadRunning = false; //notifies the worker threads of exiting
- // terminate all threads created safely.
- std::vector<HANDLE>::iterator vecIter;
- for(vecIter = threadHandlesVec.begin(); vecIter != threadHandlesVec.end(); vecIter++)
- {
- DWORD waitRes = WaitForSingleObject(*vecIter,2000);
- if(WAIT_TIMEOUT == waitRes)
- {
- printf("failed the wait for the completion port worker thread!\n");
- }
- CloseHandle(*vecIter);
- }
- threadHandlesVec.clear();
- CloseHandle(hCompletionPort);
- //delete the structs of PER_IO_OPERATION_DATA newed for clients connected.
- std::vector<PER_IO_OPERATION_DATA*>::iterator pIoDataPointerIter;
- for(pIoDataPointerIter = g_perIoDataPointerVec.begin(); pIoDataPointerIter != g_perIoDataPointerVec.end(); pIoDataPointerIter++)
- {
- closesocket((*pIoDataPointerIter)->sock);
- delete (*pIoDataPointerIter);
- *pIoDataPointerIter = 0;
- }
- g_perIoDataPointerVec.clear();
- printf(" the repeat accepting thread is exiting!\n");
- return 0;
- }
- bool ReleaseIOOperationData(PER_IO_OPERATION_DATA* & pDataToBeDeleted)
- {
- bool retVal = false;
- std::vector<PER_IO_OPERATION_DATA*>::iterator vecIter;
- for(vecIter = g_perIoDataPointerVec.begin(); vecIter != g_perIoDataPointerVec.end(); vecIter++)
- {
- if(pDataToBeDeleted == (*vecIter))
- {
- g_perIoDataPointerVec.erase(vecIter);
- closesocket(pDataToBeDeleted->sock);
- delete pDataToBeDeleted;
- pDataToBeDeleted = 0;
- retVal = true;
- break;
- }
- }
- return retVal;
- }
- DWORD WINAPI CompletionPortWorkerThread(LPVOID lpParameter)
- {
- CompletionPortWorkerThreadParam* pParam = (CompletionPortWorkerThreadParam*)lpParameter;
- bool* pStillRun = pParam->pBRunning;
- HANDLE hCompletionPort = pParam->hCompletionPort;
- DWORD dwBytesTransfered;
- PER_IO_OPERATION_DATA* pIoData;
- WSAOVERLAPPED* pOverlap;
- while(true == *pStillRun)
- {
- dwBytesTransfered = 0;
- pIoData = 0;
- pOverlap = 0;
- BOOL bGetStatus = GetQueuedCompletionStatus(hCompletionPort,&dwBytesTransfered,(PULONG_PTR)&pIoData,&pOverlap,500);
- if(FALSE == bGetStatus)
- {
- if(0 == pOverlap) //did not get a packet from the queue.
- {
- continue;
- }
- else
- {
- //get a packet for a failed I/O operation.
- }
- }
- if(OPERATION_SEND == pIoData->operationType)
- {
- if(0 == dwBytesTransfered) //a packet for a failed I/O operation.
- {
- printf("the client %d has close the socket!\n",pIoData->sock);
- ReleaseIOOperationData(pIoData);
- }
- else
- {
- // receive operation.
- pIoData->operationType = OPERATION_RECV;
- pIoData->wsaBuf.buf = pIoData->message;
- pIoData->wsaBuf.len = MESSAGE_BUF_SIZE;
- pIoData->flags = 0;
- ZeroMemory(&pIoData->overlap,sizeof(pIoData->overlap));
- int recvRes = WSARecv(pIoData->sock,&pIoData->wsaBuf,1,&pIoData->bytesRecv,&pIoData->flags,&pIoData->overlap,0);
- if(0 != recvRes && WSA_IO_PENDING != WSAGetLastError())
- {
- printf("recv error, may be the client %d has close the socket!\n",pIoData->sock);
- ReleaseIOOperationData(pIoData);
- }
- }
- }
- else if(OPERATION_RECV == pIoData->operationType)
- {
- if(0 == dwBytesTransfered) //a packet for a failed I/O operation.
- {
- printf("the client %d has close the socket!\n",pIoData->sock);
- ReleaseIOOperationData(pIoData);
- }
- else
- {
- // show the data received
- pIoData->message[dwBytesTransfered] = '\0';
- printf("the client %d:%s \n",pIoData->sock,pIoData->message);
- //send back the data received add a "server:" in the front
- char tempBuf[MESSAGE_BUF_SIZE];
- sprintf(tempBuf,"server:%s",pIoData->message);
- strcpy(pIoData->message,tempBuf);
- pIoData->operationType = OPERATION_SEND;
- pIoData->wsaBuf.buf = pIoData->message;
- pIoData->wsaBuf.len = strlen(pIoData->message);
- int sendRes = WSASend(pIoData->sock,&pIoData->wsaBuf,1,&pIoData->bytesRecv,0,0,0);
- if(0 == sendRes)
- {
- pIoData->operationType = OPERATION_RECV;
- pIoData->wsaBuf.buf = pIoData->message;
- pIoData->wsaBuf.len = MESSAGE_BUF_SIZE;
- pIoData->flags = 0;
- ZeroMemory(&pIoData->overlap,sizeof(pIoData->overlap));
- int recvRes = WSARecv(pIoData->sock,&pIoData->wsaBuf,1,&pIoData->bytesRecv,&pIoData->flags,&pIoData->overlap,0);
- if(0 != recvRes && WSA_IO_PENDING != WSAGetLastError())
- {
- printf("recv error, may be the client %d has close the socket!\n",pIoData->sock);
- ReleaseIOOperationData(pIoData);
- }
- }
- else if(SOCKET_ERROR == sendRes && WSA_IO_PENDING == WSAGetLastError())
- {
- }
- else
- {
- printf("send error, maybe the client %d has close the socket!\n",pIoData->sock);
- ReleaseIOOperationData(pIoData);
- }
- }
- }
- }
- printf("a completion port thread is exiting!\n");
- return 0;
- }
Windows socket之最简单的socket程序的更多相关文章
- python socket编程 实现简单p2p聊天程序
目标是写一个python的p2p聊天的项目,这里先说一下python socket的基础课程 一.Python Socket 基础课程 Socket就是套接字,作为BSD UNIX的进程通信机制,取后 ...
- [JavaWeb基础] 024.Socket编程之简单的聊天程序
1.Socket的简介 1)什么是Socket 网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket.Socket通常用来实现客户方和服务方的连接.Socket ...
- 基于socket实现的简单的聊天程序
记得八年前第一次使用socket做的一个五子棋程序,需要序列化棋子对象,传递到对方的电脑上. 一个偶然的机会,第二次使用socket做点事情.先看聊天服务器端的实现: 服务器端要实现以下功能: ...
- Java网络编程以及简单的聊天程序
网络编程技术是互联网技术中的主流编程技术之一,懂的一些基本的操作是非常必要的.这章主要讲解网络编程,UDP和Socket编程,以及使用Socket做一个简单的聊天软件. 全部代码下载:链接 1.网络编 ...
- Socket编程实践(3) 多连接服务器实现与简单P2P聊天程序例程
SO_REUSEADDR选项 在上一篇文章的最后我们贴出了一个简单的C/S通信的例程.在该例程序中,使用"Ctrl+c"结束通信后,服务器是无法立即重启的,如果尝试重启服务器,将被 ...
- 简单的聊天程序,主要用到的是Socket
服务端: import java.io.*; import java.net.*; import java.util.*; public class ChatServer { boolean stat ...
- socket实例C语言:一个简单的聊天程序
我们老师让写一个简单的聊天软件,并且实现不同机子之间的通信,我用的是SOCKET编程.不废话多说了,先附上代码: 服务器端server.c #include <stdio.h> #incl ...
- 局域网内python socket实现windows与linux间简单的消息传送
有个需求,就是在windows上看见一篇介绍linux相关的文章,想在局域网内的另外一台linux电脑上尝试一下, 于是就需要把该网页链接发送给linux,不想一点一点敲链接,又苦于没有找到其它好的方 ...
- 【总结】学习Socket编写的聊天室小程序
1.前言 在学习Socket之前,先来学习点网络相关的知识吧,自己学习过程中的一些总结,Socket是一门很高深的学问,本文只是Socket一些最基础的东西,大神请自觉绕路. 传输协议 TCP:Tra ...
随机推荐
- 大约Android 了解权限管理
如Android应用程序开发人员.为android权限机制一直觉得很奇怪.为什么要这个东西权限?为什么要AndroidManifest里面写的uses-permission 这样的事情?我一直搞不清楚 ...
- 【Java技术位】——代理模式及其事务包
背景 项目中我们会遇到这种情况:在几个方法中增加同样的代码,这些代码是与业务无关的,而且以后有可能因为考虑不周或需求变动再或者是其它原因,我们须要对他们进行逐一进行修改.举个详细的样例,比方程序中的日 ...
- Java中关于OOM的场景及解决方法(转)
http://developer.51cto.com/art/201112/305696.htm 1.OOM for Heap=>例如:java.lang.OutOfMemoryError: J ...
- ubuntu突然卡住
ctrl+alt+f1.进username和password.然后进入: killall gnome-sesseion sudo pkill X 版权声明:本文博主原创文章,博客,未经同意不得转载.
- Redis被攻击
记一次Redis被攻击的事件 最近几个月非常忙,所以很少有时间写博客,这几天终于闲了一些,于是就在整理平时的一些笔记.恰好这几天Redis服务器发生了问题,就记录一下. 我司有两款分别是2B和2C ...
- 通过配置Windows 防火墙允许使用TCP/IP协议远程访问数据库
原文:通过配置Windows 防火墙允许使用TCP/IP协议远程访问数据库 本文适用于:2005.2008.2008R2所有版本 为了可以通过TCP/IP协议远程访问SQLServer数据库,需要做以 ...
- Vijos.1096 津津储蓄计划
见问题: https://vijos.org/p/1096 主题概述 津津的零花钱一直都是自己的管理.每月初的母亲津津300美元,津津将于本月支出预算.而且总是做同样的实际支出与预算. 为了让津津学 ...
- 它们的定义TextView使之具有跑马灯的效果
一.引入问题 使用通用textview快乐效应,焦点事件不启动滚动,button目前的焦点事件,但丑,因此,需要定制TextView 天生焦点 个textview FocusedTextView.ja ...
- ASP.Net中使用XMLDataSource
在Web开发中,程序和数据库打交道是常有的事情.在平时使用过程中,使用较多的是MS SQLSERVER,因此经常用到SQLDataSource将数据绑定的数据控件上.有时数据量较小,无需要在数据库中创 ...
- BI—脚不一样的感觉
在这个网络智能的时代,假设生活和智能挂不上边那就太落后啦!尤其IT行业更是如此,前不久还在用微软的office做报表,这几天就吵吵着换成BI,那么BI是什么?有什么用?怎么用?等等带着这一系列的问题来 ...