TCP部分:
参考:http://blog.csdn.net/sbfksmq/article/details/50808863
另附:linux下的tcp/udp参考:https://www.cnblogs.com/lyggqm/p/9111010.html
TCP_SEVER:
// winsocketTCPServer.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" //服务器 #include<iostream> #include<WinSock2.h> // socket 所需要的头文件 #pragma comment(lib,"WS2_32.lib")// link socket 库 #define PORT 9999 #define BUFLEN 1024 using namespace std; int main() { WSADATA wsaData; // 1 启动并初始化winsock(WSAStarup) if (WSAStartup(MAKEWORD(2, 2), &wsaData))//成功返回0 { return FALSE; } //2 创建套接字(socket) SOCKET sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == sServer) { WSACleanup(); return FALSE; } //3 准备通信地址 SOCKADDR_IN addrServer; addrServer.sin_family = AF_INET; addrServer.sin_port = htons(PORT); addrServer.sin_addr.s_addr = INADDR_ANY;//任意可用地址 //4 绑定地址与socket(bind) if (SOCKET_ERROR == bind(sServer, (const sockaddr*)&addrServer, sizeof(SOCKADDR_IN))) { closesocket(sServer); WSACleanup(); return FALSE; } //5 监听 (listen) if (SOCKET_ERROR == listen(sServer, SOMAXCONN)) { closesocket(sServer); WSACleanup(); } // 6 等待客户端连接(accpet) sockaddr_in addrClient; int addrClientLen = sizeof(addrClient); cout << "服务器启动成功,等待客户端连接中。。。。" << endl; SOCKET sClient = accept(sServer, (sockaddr *)&addrClient, &addrClientLen); if (INVALID_SOCKET == sClient) { cout << WSAGetLastError() << endl; closesocket(sServer); closesocket(sClient); WSACleanup(); return FALSE; } //7 接收数据(recv) char recvBuf[BUFLEN]; ZeroMemory(recvBuf, sizeof(recvBuf)); if (SOCKET_ERROR == recv(sClient, recvBuf, sizeof(recvBuf), 0)) { closesocket(sServer); closesocket(sClient); WSACleanup(); return FALSE; } cout << "客户端(" << inet_ntoa(addrClient.sin_addr) << ":" << addrClient.sin_port << "):" << recvBuf << endl; //8 发送数据 char sendBuf[BUFLEN] = "你好客户端!"; if (SOCKET_ERROR == send(sClient, sendBuf, sizeof(sendBuf), 0)) { closesocket(sServer); closesocket(sClient); WSACleanup(); return FALSE; } system("pause"); system("pause"); return TRUE; } /* 注:1:MAKEWORD把参数组成一个WORD(双字节)类型数据并返回这个WORD类型数值,高位代表(修订本)号,低位字节指定主版本号(其代表) 2:socket(AF_INET,//The Internet Protocol version 4 (IPv4) address family SOCK_STREAM,//, two-way,This socket type uses the Transmission Control Protocol (TCP) for the Internet address family (AF_INET or AF_INET6). IPPROTO_TCP//The Transmission Control Protocol (TCP). This is a possible value when the af parameter is AF_INET or AF_INET6 and the type parameter is SOCK_STREAM. ) */
TCP_CLIENT:
// winsocketTCPClient.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" //客户端 #include<iostream> #include<WinSock2.h> #pragma comment(lib,"WS2_32.lib") using namespace std; #define BUFLEN 1024 #define PORT 9999 void getIP(char*szHostaddress); int main() { WSADATA wsaData; // 1 启动并初始化winsock(WSAStarup) if (WSAStartup(MAKEWORD(2, 2), &wsaData))//成功返回0 { return FALSE; } //2 创建套接字(socket) SOCKET sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == sHost) { closesocket(sHost); WSACleanup(); return FALSE; } //3 准备通信地址 char szHostaddress[200]; getIP(szHostaddress); SOCKADDR_IN addrServer; addrServer.sin_family = AF_INET; addrServer.sin_port = htons(PORT); addrServer.sin_addr.s_addr = inet_addr(szHostaddress); //4 连接服务器(connect) if (SOCKET_ERROR == connect(sHost, (const sockaddr*)&addrServer, sizeof(addrServer))) { closesocket(sHost); WSACleanup(); return FALSE; } //5 发送数据 (send) char sendBuf[BUFLEN] = "你好服务器!"; if (SOCKET_ERROR == send(sHost, sendBuf, sizeof(sendBuf), 0)) { closesocket(sHost); WSACleanup(); return FALSE; } cout << "客户端发送消息成功!" << endl; //7 接收数据(recv) char recvBuf[BUFLEN]; ZeroMemory(recvBuf, sizeof(recvBuf)); if (SOCKET_ERROR == recv(sHost, recvBuf, sizeof(recvBuf), 0)) { closesocket(sHost); WSACleanup(); return FALSE; } cout << "服务器发来的消息:" << recvBuf << endl; system("pause"); } void getIP(char*szHostaddress) { char szHostname[100]; if (gethostname(szHostname, sizeof(szHostname)) != SOCKET_ERROR)//先得到主机名 { HOSTENT *pHostEnt = gethostbyname(szHostname);//通过名字拿到地址 if (pHostEnt != NULL) { sprintf(szHostaddress, "%d.%d.%d.%d", (pHostEnt->h_addr_list[0][0] & 0x00ff), (pHostEnt->h_addr_list[0][1] & 0x00ff), (pHostEnt->h_addr_list[0][2] & 0x00ff), (pHostEnt->h_addr_list[0][3] & 0x00ff)); } } else return; }
UDP部分:
参考:http://blog.csdn.net/sbfksmq/article/details/51046439
UDP_SERVER:
// 服务端 // UDP.cpp : 定义控制台应用程序的入口点。 //1 为UDP通信,单例模式 //2 一些socket函数不兼容 预处理器定义里添加如下的宏 //_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE; //3 UDP为非面向连接方式不需要listen 与accept #include"stdafx.h" #include"afxwin.h" #include"WinSock2.h" #include<iostream> #include <ws2tcpip.h> #pragma comment(lib,"WS2_32.lib") using namespace std; //日志 可以不看 bool WriteErrorLogFile(CString csData)// errorlog { char buff[256]; CString ErrorLog; GetModuleFileName(NULL, (LPWSTR)buff, sizeof(buff)); cout << buff << endl; ErrorLog = CString(buff); ErrorLog += ErrorLog.Left(ErrorLog.ReverseFind('\')) + "\ErrorLog"; CString stemp; CString sPathName; SYSTEMTIME sys_time; GetLocalTime(&sys_time); sPathName = ErrorLog; stemp.Format(L"%d%d%d", sys_time.wYear, sys_time.wMonth, sys_time.wDay); sPathName += "\" + stemp; CreateDirectory(sPathName, NULL); CStdioFile f; if (!f.Open(sPathName, CStdioFile::modeCreate | CStdioFile::modeNoTruncate | CStdioFile::modeWrite | CStdioFile::typeText)) { return false; } f.SeekToEnd(); stemp.Format(L"%02d:%02d:%02d:%s ", sys_time.wHour, sys_time.wMinute, sys_time.wSecond, csData); f.WriteString(stemp); f.Flush(); f.Close(); return true; } class UDPSERVER {//私有 UDPSERVER(char *ip, char*port) :m_IP(ip), m_Port(port) { m_srvSocket = INVALID_SOCKET; //init // Init(); } UDPSERVER(UDPSERVER const &that) { } public: static UDPSERVER *Instance(char*ip,char*port) { if (!_instance) { _instance = new UDPSERVER(ip, port); } return _instance; } static bool Init() { WSADATA wsaData; try { if (WSAStartup(0X202, &wsaData))//If successful, the WSAStartup function returns zero { int err = WSAGetLastError(); WSACleanup(); return true; } } catch (...) { cout << "WSAStartup error code:" << WSAGetLastError() << endl; return false; } return true; } static bool GetLocalIp(char *szIP)// 获取IP { char szHostName[128]; ZeroMemory(szHostName, sizeof(szHostName)); if (gethostname(szHostName, sizeof(szHostName))== 0)//gethostname 函数要在WSAStartup后进行调用。。。 { // cout << "szHostName = " <<szHostName<< endl; HOSTENT*pHostEnt = gethostbyname(szHostName); if (pHostEnt) { sprintf(szIP, "%d.%d.%d.%d", (pHostEnt->h_addr_list[0][0] & 0xff), (pHostEnt->h_addr_list[0][1] & 0xff), (pHostEnt->h_addr_list[0][2] & 0xff), (pHostEnt->h_addr_list[0][3] & 0xff)); //cout<<szIP<<endl; return true; } } else { cout << "gethostname error code:" << WSAGetLastError()<<endl; return false; } return true; } bool StartServer() { // create socket m_srvSocket = socket(AF_INET, SOCK_DGRAM, 0); if (INVALID_SOCKET == m_srvSocket) { WSACleanup(); char errBuf[16]; WriteErrorLogFile(CString(itoa(WSAGetLastError(), errBuf, sizeof(errBuf)))); return false; } // address pAddrServer.sin_family = AF_INET; pAddrServer.sin_port = htons(atoi(m_Port)); pAddrServer.sin_addr.s_addr = inet_addr(m_IP);//or INADDR_ANY:接收任意IP发来的数据或指定一个IP发送数据 //bind if (bind(m_srvSocket, (const sockaddr*)&pAddrServer, sizeof(SOCKADDR_IN))) { WSACleanup(); closesocket(m_srvSocket); char errBuf[16]; WriteErrorLogFile(CString(itoa(WSAGetLastError(), errBuf, sizeof(errBuf)))); return false; } //jUDP no need to listen or accept return true; } void RcvData(char*buff = NULL) { int nSrvAddrLen = sizeof(SOCKADDR); char bufMessage[1024]; ZeroMemory(bufMessage, sizeof(bufMessage)); int nRetRcv = recvfrom(m_srvSocket, bufMessage, sizeof(bufMessage), 0, (sockaddr*)&pAddrServer, (int *) &nSrvAddrLen); /*recv,send,(TCP)从一个已连接的socket接收或发送数据 sendto,recvfrom(UDP/TCP):从一个已连接或未连接的socket接收或发送数据 当你对于数据报socket调用了connect()函数时,你也可以利用send()和recv()进行数据传输, 但该socket仍然是数据报socket,并且利用传输层的UDP服务。但在发送或接收数据报时,内核会自动为之加上目地和源地址信息。*/ //不管是recv还是recvfrom,都有两种模式,阻塞和非阻塞,可以通过ioctl函数来设置 if (0 == nRetRcv) { WSACleanup(); closesocket(m_srvSocket); char errBuf[16]; WriteErrorLogFile(CString(itoa(WSAGetLastError(), errBuf, sizeof(errBuf)))); } cout << "the client:"<<inet_ntoa(pAddrServer.sin_addr)<<" say:" << bufMessage << endl; } void SentData(char*buff=NULL) { // sendto SOCKADDR_IN clientAddr; clientAddr.sin_family = AF_INET; clientAddr.sin_port = htons((short)6666);//发送到的端口 clientAddr.sin_addr.s_addr = inet_addr(m_IP); int nRetSent = sendto(m_srvSocket,"hello client",sizeof("hello client"),0, (SOCKADDR*)&clientAddr, sizeof(clientAddr)); if (0 == nRetSent) { WSACleanup(); closesocket(m_srvSocket); char errBuf[16]; WriteErrorLogFile(CString(itoa(WSAGetLastError(), errBuf, sizeof(errBuf)))); } } private: char *m_IP; char *m_Port; SOCKET m_srvSocket; SOCKADDR_IN pAddrServer ; static UDPSERVER* _instance; }; UDPSERVER*UDPSERVER::_instance = NULL; int main(int argc,char*argv[]) { char szIP[16] = {}; UDPSERVER::Init(); if (false != UDPSERVER::GetLocalIp(szIP)) { UDPSERVER* pUdpServer = UDPSERVER::Instance(szIP, "8888"); if (pUdpServer->StartServer()) { while (1) { pUdpServer->RcvData(); pUdpServer->SentData(); } } else { delete pUdpServer; pUdpServer = NULL; } } system("pause"); return 0; }
UDP_CLIENT:
//客户端 #include "stdafx.h" #include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #include<iostream> #pragma comment (lib, "Ws2_32.lib") using namespace std; int main(int argc, char **argv) { //1 初始化 WSADATA wsaData; SOCKET sServer; WSAStartup(0x202, &wsaData); //2 创建绑定socket sServer = socket(AF_INET, SOCK_DGRAM, 0); SOCKADDR_IN srvAddr; srvAddr.sin_family = AF_INET; srvAddr.sin_port = htons(6666); srvAddr.sin_addr.s_addr = inet_addr("172.168.28.201"); bind(sServer, (const sockaddr*)&srvAddr, sizeof(srvAddr)); //3 准备数据传输目的地的地址与数据 int nSrvAddrLen = sizeof(srvAddr); char szSendBuff[1024]; ZeroMemory(szSendBuff, sizeof(szSendBuff)); memcpy(szSendBuff, "hello server", sizeof("hello server")); SOCKADDR_IN cltAddr; cltAddr.sin_family = AF_INET; cltAddr.sin_port = htons(8888);// 发送到哪个端口 htons主机字节顺序转变成网络字节顺序 cltAddr.sin_addr.s_addr = inet_addr("172.168.28.201");//inet_addr 字符串转换为32位二进制网络字节序的IPV4地址 int nCltAddrLen = sizeof(cltAddr); // 发送 sendto(sServer, szSendBuff, sizeof(szSendBuff), 0, (const sockaddr*)&cltAddr, nCltAddrLen); // 接收 memset(szSendBuff, 0, sizeof(szSendBuff)); recvfrom(sServer, szSendBuff, sizeof(szSendBuff), 0, ( sockaddr*)&srvAddr, &nSrvAddrLen); /*inet_pton inetntop 可以在将IP地址在“点分十进制”和“网络二进制结构”之间转换。而且,这2个函数能够处理ipv4和ipv6。算是比较新的函数*/ struct protoent *pe = getprotobyname("udp"); //getpeername(sServer, (sockaddr*)&srvAddr, &nSrvAddrLen); cout << "the client receive the message: " << endl; cout << "/* the server ip:" << inet_ntoa(srvAddr.sin_addr) << endl;//inet_ntoa 将网络地址转换成“.”点隔的字符串格式 cout << " the server port is " <<ntohs(srvAddr.sin_port) << endl;//htons cout << " the server protocol:" << pe->p_name << endl; cout << " the server protocal num is " << pe->p_proto << endl; cout << " the server message is : "<< szSendBuff << " */ " << endl; system("pause"); return 0; }
SELECT部分:
参考:http://blog.csdn.net/sbfksmq/article/details/51051585
SELECT_SERVER:
// WinSelectModel.cpp : 定义控制台应用程序的入口点。 // //server side ,select model /* Syntax: int select( _In_ int nfds,//Ignored. The nfds parameter is included only for compatibility with Berkeley sockets. _Inout_ fd_set *readfds,//An optional pointer to a set of sockets to be checked for readability. _Inout_ fd_set *writefds,//An optional pointer to a set of sockets to be checked for writability. _Inout_ fd_set *exceptfds,//An optional pointer to a set of sockets to be checked for errors. _In_ const struct timeval *timeout//The maximum time for select to wait, provided in the form of a TIMEVAL structure. Set the timeout parameter to null for blocking operations. ) 功能:简单的讲就是一个socket“复用器”(不必为第个客户建立新线程,但需要不断轮询fd_set检测,fd_set的大小固定64),它能够检测报告一个或多个socket状态 ,但不如WSAASyncSelct()那么细致,第次调用,select ()把一组socket作为输入参数,而且它是阻塞的(可设置),也就是说该函数能使你同时检测多个socket的状态,它需要通过返回值来带回执行结果 Return value:成功返回当前状态与设定状态相匹配的socket的总数,超时返回0(timeout参数),失败返回SOCKET_ERROR remarks:它与BSD兼容 ,也可以使用WSAAsyncSelect() ,timeout非零则阻塞,零则不阻塞(但不要传NULL为无限阻塞) 应用:网络连接数不大的程序 与select配合使用的宏 FD_ZERO(*set) :对fd_set初始化 FD_SET(s, *set):添加指定s套接字至集合 FD_CLR(s, *set):删除指定s套接字至集合 FD_ISSET(s, *set):检查指定s套接字是否集合 FD_SETSIZE: 64 */ #include "stdafx.h" #include<iostream> #include<WinSock2.h> // socket 所需要的头文件 #pragma comment(lib,"WS2_32.lib")// link socket 库 #define PORT 6666 #define BUFLEN 1024 using namespace std; fd_set g_fdClientSocket; //fd_set DWORD WINAPI ThreadProc(LPVOID lpParameter); int main() { DWORD dwThreadID; sockaddr_in addrClient; int addrClientLen = sizeof(addrClient); SOCKET sServer = INVALID_SOCKET; SOCKET sClient; int nClientCount = 0; // 1 启动并初始化winsock(WSAStarup) WSADATA wsaData; if (WSAStartup(0x202, &wsaData))//成功返回0 { return FALSE; } //2 创建套接字(socket) sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == sServer) { WSACleanup(); return FALSE; } //3 准备通信地址 SOCKADDR_IN addrServer; addrServer.sin_family = AF_INET; addrServer.sin_port = htons(PORT);//服务器用于监听的端口号,客户端需要知道这个端口进行连接 addrServer.sin_addr.s_addr = INADDR_ANY; //4 绑定地址与socket(bind) if (SOCKET_ERROR == bind(sServer, (const sockaddr*)&addrServer, sizeof(SOCKADDR_IN))) { closesocket(sServer); WSACleanup(); return FALSE; } //5 监听 (listen) if (SOCKET_ERROR == listen(sServer, SOMAXCONN)) { closesocket(sServer); WSACleanup(); } //6 线程利用select()处理可读的客户端 CreateThread(NULL, 0, ThreadProc, NULL, 0, &dwThreadID); // 7 等待多个客户端连接(accpet) while (nClientCount<FD_SETSIZE) { sClient= accept(sServer, (sockaddr *)&addrClient, &addrClientLen); if (INVALID_SOCKET == sClient) { cout << WSAGetLastError() << endl; //或根据错误码进行其他操作 closesocket(sServer); closesocket(sClient); WSACleanup(); return FALSE; } printf("Accepted client:%s:%d ", inet_ntoa(addrClient.sin_addr), ntohs(addrClient.sin_port)); FD_SET(sClient,& g_fdClientSocket); nClientCount++; } system("pause"); return TRUE; } // 只处理是可读状态的socket DWORD WINAPI ThreadProc(LPVOID lpParameter) { fd_set fdRead; fd_set fdWrite; FD_ZERO(&fdRead); FD_ZERO(&fdWrite); int nRet = 0; char recvBuffer[1024] = {}; struct timeval stTimeOut = { 1,0 }; while (true) { fdRead = g_fdClientSocket; fdWrite = g_fdClientSocket; nRet = select(0, &fdRead, &fdWrite, NULL, &stTimeOut); if (SOCKET_ERROR != nRet) { for (int i = 0; i < g_fdClientSocket.fd_count; i++) { if (FD_ISSET(g_fdClientSocket.fd_array[i], &fdRead)) { memset(recvBuffer, 0, sizeof(recvBuffer)); SOCKADDR_IN stAddrTemp; int nTempLen = sizeof(stAddrTemp); nRet = recvfrom(g_fdClientSocket.fd_array[i], recvBuffer, sizeof(recvBuffer), 0, (sockaddr*)&stAddrTemp, &nTempLen); if (SOCKET_ERROR == nRet) { closesocket(g_fdClientSocket.fd_array[i]); FD_CLR(g_fdClientSocket.fd_array[i], &g_fdClientSocket); } else { cout << "the client(" << inet_ntoa(stAddrTemp.sin_addr) << ":" << ntohs(stAddrTemp.sin_port) << ") :" << recvBuffer << "(message size is " << nTempLen << ")" << endl; } } if (FD_ISSET(g_fdClientSocket.fd_array[i], &fdWrite)) { nRet = send(g_fdClientSocket.fd_array[i], "hello Client", sizeof("hello Client"), 0); if (SOCKET_ERROR == nRet) { int nErrorNo = WSAGetLastError(); cout << "send error code is " << nErrorNo << endl;//10038 socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid. closesocket(g_fdClientSocket.fd_array[i]); FD_CLR(g_fdClientSocket.fd_array[i], &g_fdClientSocket); } else { continue; } } } } } }
SELECT_CLIENT:
// WinSelectClient.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include<WinSock2.h> //客户端 #include<iostream> #pragma comment(lib,"WS2_32.lib") using namespace std; #define BUFLEN 1024 #define PORT 6666 void getIP(char*szHostaddress); void SendProc(); SOCKET sHost; int main() { WSADATA wsaData; // 1 启动并初始化winsock(WSAStarup) if (WSAStartup(MAKEWORD(2, 2), &wsaData))//成功返回0 { return FALSE; } //2 创建套接字(socket) sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == sHost) { closesocket(sHost); WSACleanup(); return FALSE; } //3 准备通信地址 char szHostaddress[200]; getIP(szHostaddress); SOCKADDR_IN addrServer; addrServer.sin_family = AF_INET; addrServer.sin_port = htons(PORT); addrServer.sin_addr.s_addr = inet_addr(szHostaddress); //4 连接服务器(connect) if (SOCKET_ERROR == connect(sHost, (const sockaddr*)&addrServer, sizeof(addrServer)))//连接到指定的地址 { closesocket(sHost); WSACleanup(); return FALSE; } //5 发送数据 (send) char sendBuf[BUFLEN] = "你好服务器!"; if (SOCKET_ERROR == send(sHost, sendBuf, sizeof(sendBuf), 0)) { closesocket(sHost); WSACleanup(); return FALSE; } cout << "客户端发送消息成功!" << endl; //7 接收数据(recv) char recvBuf[BUFLEN]; ZeroMemory(recvBuf, sizeof(recvBuf)); if (SOCKET_ERROR == recv(sHost, recvBuf, sizeof(recvBuf), 0)) { closesocket(sHost); WSACleanup(); return FALSE; } cout << "服务器发来的消息:" << recvBuf << endl; while (true) { SendProc(); Sleep(1000); } system("pause"); } void SendProc( ) { char sendBuf[BUFLEN] = "你好服务器!"; if (SOCKET_ERROR == send(sHost, sendBuf, sizeof(sendBuf), 0)) { closesocket(sHost); WSACleanup(); return ; } cout << "客户端发送消息成功!" << endl; } void getIP(char*szHostaddress) { char szHostname[100]; if (gethostname(szHostname, sizeof(szHostname)) != SOCKET_ERROR)//先得到主机名 { HOSTENT *pHostEnt = gethostbyname(szHostname);//通过名字拿到地址 if (pHostEnt != NULL) { sprintf(szHostaddress, "%d.%d.%d.%d", (pHostEnt->h_addr_list[0][0] & 0x00ff), (pHostEnt->h_addr_list[0][1] & 0x00ff), (pHostEnt->h_addr_list[0][2] & 0x00ff), (pHostEnt->h_addr_list[0][3] & 0x00ff)); } } else return; }