服务端
#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <unistd.h>#include <iostream>#include <string.h>// 对于服务器, 通信流程一般是:// 1. 调用socket函数创建socket// 2. 调用bind函数将socket绑定到某个ip和端口的二元组上// 3. 调用listen函数开启监听// 4. 当有客户端请求连接上来时,调用accept函数接收连接,产生一个新socket(客户端socket)// 5. 基于新产生的socket调用s或secv函数,开始与客户端进行数据交流// 6. 通信结束后,调用close函数关闭监听socketint main(){ // 1. create socket int listenfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == listenfd) { std::cout << "create listen socket error." << std::l; return -1; } // 2. init service struct sockaddr_in bindaddr; bindaddr.sin_family = AF_INET; bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); bindaddr.sin_port = htons(3000); if (bind(listenfd, (struct sockaddr*)&bindaddr, sizeof(bindaddr)) == -1) { std::cout << "bind listen socket error." << std::l; return -1; } // 3. listen if (listen(listenfd, SOMAXCONN) == -1) { std::cout << "listen socket error." << std::l; return -1; } while (true) { struct sockaddr_in clientaddr; socklen_t clientaddrlen = sizeof(clientaddr); // 4. accept conn int clientfd = accept(listenfd, (struct sockaddr*)&clientaddr, &clientaddrlen); if (-1 != clientfd) { char recvBuf[32] = {0}; // 5. get message from client int ret = recv(clientfd, recvBuf, 32, 0); if (ret > 0) { std::cout << "recv data from client, data: " << recvBuf << std::l; // 6. set message to client ret = s(clientfd, recvBuf, strlen(recvBuf), 0); if (ret != strlen(recvBuf)) { std::cout << "s data error" << std::l; } else { std::cout << "s data to client successfully, data: " << recvBuf << std::l; } } else { std::cout << "recv data error" << std::l; } close(clientfd); } } // 7. close socket close(listenfd); return 0;}
客户端
#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <unistd.h>#include <iostream>#include <string.h>#define SERVER_ADDRESS "127.0.0.1"#define SERVER_PORT 3000#define S_DATA "hello world"// 对于客户端, 通信流程一般是:// 1. 调用socket函数创建socket// 2. 调用connect函数尝试连接服务器// 3. 连接成功后,调用s或secv函数,开始与服务器进行数据交流// 4. 通信结束后,调用close函数关闭监听socketint main(){ // 1. create socket int clientfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == clientfd) { std::cout << "create client socket error." << std::l; return -1; } // 2. client server struct sockaddr_in serveraddr; serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = inet_addr(SERVER_ADDRESS); serveraddr.sin_port = htons(SERVER_PORT); if (connect(clientfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) == -1) { std::cout << "connect socket error." << std::l; return -1; } // 3. s message to server int ret = s(clientfd, S_DATA, strlen(S_DATA), 0); if (ret != strlen(S_DATA)) { std::cout << "s data error." << std::l; return -1; } std::cout << "s data success. data: " << S_DATA << std::l; // 4. get message from server char recvBuf[32] = {0}; ret = recv(clientfd, recvBuf, 32, 0); if (ret > 0) { std::cout << "recv data success. data: " << S_DATA << std::l; } else { std::cout << "recv data error." << std::l; } // 5. close socket close(clientfd); return 0;}
基本函数说明
// 在windows上,一个socket对象类型是SOCKET,在linux上,一个socket对象类型是int。#ifdef WIN32typedef SOCKET SOCKET_TYPE#elsetypedef int SOCKET_TYPE#if// Linux上可以直接使用socket函数,但对于Windows,必须先调用WSAStartup函数显式的将与socket函数相关的dll文件加载到进程地址中,在退出时需要调用WSACleanup函数卸载相关的dll文件bool InitSocket(){ WORD wVersionRequested = MAKEWORD(2, 2); WSADATA wsaData; int nErrorId = ::WSAStartup(wVersionRequested, &wsaData); if (nErrorId != 0) { return false; } if (LOBYTE(wsaData.wVersion) != 2
HIBYTE(wsaData.wVersion) != 2) { UninitSocket(); return false; } return true;}void UninitSocket(){ ::WSACleanup();}// 在Linux上使用close函数关闭socket,在windows上使用closesocket函数。// Windows也定义了一个close函数, 如果关闭socket使用了close函数,则会导致程序崩溃。#ifndef WIN32#define closesocket(s) close(s)#if// 在window上使用WASGetLastError()函数获取错误码,在Linux上则使用error变量获取错误码#ifdef WIN32#define GetSocketLastError() WASGetLastError()#else #define GetSocketLastError() error#if// 无论时Windows还是Linux,大多数socket函数在调用失败后都会返回-1,在Windows上专门定义了一个宏 SOCKET_ERROR