基于TCP的简单socket通信
2013-05-09 15:38
411 查看
前两天开始翻看UNIX网络编程,看到了一个基于TCP的socket通信实例(客户端向服务器请求当前时间),于是自己在vs上实现了下,以加深对socket通信流程的了解,代码如下:
客户端
服务器端
工具
在windows中,客户端程序的流程是 初始化winsock库->创建socket->创建服务器地址(端口和IP)->请求连接->接收响应数据->释放资源
服务器端的流程是 初始化winsock库->创建监听socket->创建监听地址->将监听socket文件描述符与监听地址绑定->开始监听->接收请求->处理请求并响应->继续等待请求
客户端输出结果:
服务器端输出结果(客户端运行四次):
以上的程序可以成功的在客户端输出向服务器请求到的时间,但是我对服务器端getpeername(nConnectedSock,(sockaddr *)&clientAddr,&nSize)得到的客户端机器的地址值不是很理解,我本以为服务器端监听到的socket描述符(88)应该和客户端创建的socket描述符(84) 是相等的,而且端口号也应该是相等的(2013),但每次接到的请求端口号都增加1,该问题有待解决。
补充:
通过向朋友请教并查看资料,对以上提出的两个疑问有了理解。
(1)当服务器端收到一个请求后服务器会产生一个socket句柄,他和客户端创建的是不一样的,这个新产生的句柄是用来连接客户端和服务器的;
(2)服务器收到的请求的客户机的地址中端口一直在变,是因为客户端在通信时是不用绑定端口的,内核会选择一个可用端口进行通信,所以会变。
客户端
#include <windows.h> #include <iostream> #include <cassert> #include <io.h> #include "../../Server/Server/SocketUtil.h" #pragma comment(lib, "Ws2_32.lib") const int ServerPort = 2013; const char* pServerIP = "127.0.0.1"; int main() { //初始化winsock WSAData wsaData; memset(&wsaData, NULL, sizeof(WSAData)); if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { RecordError("init winsock failed"); return 0; } SocketHolder sholder; //创建socket int sockFd = 0; if ((sockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { RecordError("socket create error"); return 0; } sholder.SetSocketFd(sockFd); //初始化socket地址 sockaddr_in servAddr; //sockaddr_in最后8个字节用于占位,为了与sockaddr大小一致 memset(&servAddr, NULL, sizeof(sockaddr_in)); servAddr.sin_family = AF_INET; /* * htons将host字节序排列的数转化为network字节序排列的short类型(端口号是16位的) * ServerPort=13,在本地按主机字节序存储为(按16位)0000 0000 0000 1101, * 转化为网络字节序为0000 1101 0000 0000,为3328 */ servAddr.sin_port = htons(ServerPort); assert(pServerIP); /* * inet_pton将标准文本形式的IP地址转化为数字二进制形式 * server ip为127.0.0.1 * s_addr=1<<24 + 127=16777343,IP地址为32位 */ servAddr.sin_addr.s_addr = inet_addr(pServerIP); //请求连接服务器 std::cout<<"start connect ..."<<std::endl; if (connect(sockFd, (sockaddr*)(&servAddr), sizeof(servAddr)) < 0) { //10061:服务器拒绝连接 10060:连接超时 RecordError("connect failed"); return 0; } std::cout<<"host sockfd = "<<sockFd<<std::endl; PrintClientConnectInfo(servAddr); std::cout<<std::endl; std::cout<<"connect successed"<<std::endl; int nCount = 0; char buf[MAX_PATH] = {0}; while ((nCount = recv(sockFd, buf, sizeof(buf), 0)) > 0) { std::cout<<buf; memset(buf, NULL, sizeof(buf)); } return 0; }
服务器端
#include <Windows.h> #include <ctime> #include <iostream> #include <io.h> #include "SocketUtil.h" #pragma comment(lib, "Ws2_32.lib") const int ServerPort = 2013; int main () { WSAData wsaData; memset(&wsaData, NULL, sizeof(WSAData)); if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { RecordError("init winsock failed"); return 0; } SocketHolder sholder; int nListeningSocket = socket(AF_INET, SOCK_STREAM, 0); if (nListeningSocket < 0) { RecordError("listening socket create error"); return 0; } sholder.SetSocketFd(nListeningSocket); sockaddr_in serverAddr; memset(&serverAddr, NULL, sizeof(sockaddr_in)); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(ServerPort); serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); int nBindResult = bind(nListeningSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)); if (nBindResult != 0) { RecordError("server bind failed"); return 0; } int nListeningResult = listen(nListeningSocket, 5); if (nListeningResult != 0) { RecordError("listen failed"); return 0; } int nConnectedSock = INVALID_SOCKET; time_t t = 0; char timeBuf[MAX_PATH] = {0}; std::cout<<"start server ..."<<std::endl; while (true) { nConnectedSock = accept(nListeningSocket, (sockaddr*)NULL, NULL); if (nConnectedSock == INVALID_SOCKET) { RecordError("accept failed"); continue; } sockaddr_in clientAddr; memset(&clientAddr, NULL, sizeof(clientAddr)); int nSize = sizeof(clientAddr); getpeername(nConnectedSock,(sockaddr *)&clientAddr,&nSize); std::cout<<"receive a request sockfd = "<<nConnectedSock<<" "; PrintClientConnectInfo(clientAddr); std::cout<<std::endl; t = time(NULL); sprintf_s(timeBuf, sizeof(timeBuf), "%.24s\r\n", ctime(&t)); //write(nConnectedSock, timeBuf, strlen(timeBuf)); send(nConnectedSock, timeBuf, strlen(timeBuf), 0); closesocket(nConnectedSock); } std::cout<<"stop server ..."<<std::endl; return 0; }
工具
#pragma once void int2ipstr (const int ip, char *buf); struct sockaddr_in; void PrintClientConnectInfo (const sockaddr_in& clientAddr); void RecordError(const char* pInfo); class SocketHolder { public: SocketHolder(); ~SocketHolder(); void SetSocketFd(int nSockFd); private: int m_nSockFd; };
#include "SocketUtil.h" #include <Windows.h> #include <iostream> #include <cassert> void int2ipstr (const int ip, char *buf) { sprintf_s(buf, MAX_PATH, "%u.%u.%u.%u", (unsigned char) * ((char *) &ip + 0), (unsigned char) * ((char *) &ip + 1), (unsigned char) * ((char *) &ip + 2), (unsigned char) * ((char *) &ip + 3)); } void PrintClientConnectInfo (const sockaddr_in& clientAddr) { std::cout<<"port = "<<ntohs(clientAddr.sin_port)<<","; char ip[MAX_PATH] = {0}; int2ipstr(clientAddr.sin_addr.s_addr, ip); std::cout<<"IP ="<<" "<<ip; } void RecordError(const char* pInfo) { int errorCode = WSAGetLastError(); std::cout<<pInfo<<std::endl; } SocketHolder::SocketHolder() : m_nSockFd(0) { } void SocketHolder::SetSocketFd(int nSockFd) { assert(nSockFd); m_nSockFd = nSockFd; } SocketHolder::~SocketHolder() { if(m_nSockFd > 0) closesocket(m_nSockFd); WSACleanup(); }
在windows中,客户端程序的流程是 初始化winsock库->创建socket->创建服务器地址(端口和IP)->请求连接->接收响应数据->释放资源
服务器端的流程是 初始化winsock库->创建监听socket->创建监听地址->将监听socket文件描述符与监听地址绑定->开始监听->接收请求->处理请求并响应->继续等待请求
客户端输出结果:
服务器端输出结果(客户端运行四次):
以上的程序可以成功的在客户端输出向服务器请求到的时间,但是我对服务器端getpeername(nConnectedSock,(sockaddr *)&clientAddr,&nSize)得到的客户端机器的地址值不是很理解,我本以为服务器端监听到的socket描述符(88)应该和客户端创建的socket描述符(84) 是相等的,而且端口号也应该是相等的(2013),但每次接到的请求端口号都增加1,该问题有待解决。
补充:
通过向朋友请教并查看资料,对以上提出的两个疑问有了理解。
(1)当服务器端收到一个请求后服务器会产生一个socket句柄,他和客户端创建的是不一样的,这个新产生的句柄是用来连接客户端和服务器的;
(2)服务器收到的请求的客户机的地址中端口一直在变,是因为客户端在通信时是不用绑定端口的,内核会选择一个可用端口进行通信,所以会变。
相关文章推荐
- linux网络编程之用socket实现简单客户端和服务端的通信(基于TCP)
- Java 基于TCP/IP 实现简单的 socket 通信
- Java 基于TCP/IP 实现简单的 socket 通信
- linux下基于TCP简单的socket通信程序
- 基于TCP Socket的简单网络通信
- linux网络编程之用socket实现简单客户端和服务端的通信(基于TCP)
- 基于Tcp&UDP协议的简单Socket通信实例(JAVA)
- 基于tcp的简单socket通信
- Android搭建简单的socket服务器——基于TCP
- [20180313智慧餐厅推荐系统02]基于python的socket编程代码,实现PC与服务器的简单通信
- 基于多线程的TCP socket通信经典案例
- socket 网络编程快速入门(一)教你编写基于UDP/TCP的服务(客户端)通信
- C++基于TCP/IP简单的客户端、服务器通信程序实例
- 【socket编程】 一个简单的基于TCP连接的客户端、服务端用例
- 【Java TCP/IP Socket】基于NIO的TCP通信(含代码)
- 简单socket通信过程(TCP)
- 实现采用客户/服务器通信模式,基于TCP网络通信协议的多客户端简单应用之案例分析
- C#的TcpClient和TCPSocket简单通信
- 简单使用SOCKET,TCP,UDP模式之间的通信