TCP流式套接字与I/O复用Select模型代码

C++的socket编程:实现了Server和Client端的通信,主要功能:

Server获取Client的system的时间,Server和Client互相收发文件



Server端代码:

#include "stdafx.h"
#undef UNICODE 
#define WIN32_LEAN_AND_MEAN 
#include<windows.h> 
#include<winsock2.h> 
#include<iostream>
#include<ctime>
#include<time.h>
#include<ws2tcpip.h> 
#include<stdlib.h> 
#include<stdio.h> 
#include<cstdio>
#include<cstring>
using namespace std;
#pragma comment (lib, "Ws2_32.lib") 

#define DEFAULT_BUFLEN 1024
#define DEFAULT_PORT 30000
#define DEFAULT_DATA "Hello, I' m Mr.Trojan."

#define cmdline1 "GetTime"
#define cmdline2 "SendData"
#define cmdline3 "RecvData"

int main(int argc, _TCHAR* argv[]){
    WSADATA wsaData;
    int iResult; 
	SOCKET ServerSocket = INVALID_SOCKET, AcceptSocket = INVALID_SOCKET; 
    char recvbuf[DEFAULT_BUFLEN]; 
    int recvbuflen = DEFAULT_BUFLEN; 
	sockaddr_in addrClient;
	int addrClientlen = sizeof(sockaddr_in);

    //Winsock初始化
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData); 
    if (iResult != 0) { 
		printf("WSAStartup failed: %d\n", iResult); 
	    return -1;
    } 

	// 创建监听套接字
    ServerSocket = socket(AF_INET,SOCK_STREAM, IPPROTO_IP);       
    if(ServerSocket == INVALID_SOCKET) {
        printf("socket failed: %ld\n", WSAGetLastError()); 
        WSACleanup();
        return -1;
    } 

    // 绑定地址和端口号
	SOCKADDR_IN addrServ;   
    addrServ.sin_family = AF_INET;   
    addrServ.sin_port = htons(DEFAULT_PORT);
    addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);    

    iResult = bind(ServerSocket,(const struct sockaddr*)&addrServ,sizeof(SOCKADDR_IN)); 
    if (iResult == SOCKET_ERROR) {
        printf("bind failed: %d\n", WSAGetLastError()); 
        closesocket(ServerSocket); 
        WSACleanup(); 
        return -1;
    } 

    // 监听 
    iResult = listen(ServerSocket, SOMAXCONN);   
    if(iResult == SOCKET_ERROR)   {   
        printf("listen failed !\n");   
        closesocket(ServerSocket);   
        WSACleanup();   
        return -1;   
    }

	// 开启TCP连接
	printf("TCP server starting\n");
	fd_set fdRead,fdSocket;
    FD_ZERO( &fdSocket );
	FD_SET( ServerSocket, &fdSocket);

	while(1){
		//通过select等待数据到达事件
	    fdRead = fdSocket;
		iResult = select( 0, &fdRead, NULL, NULL, NULL);

		if (iResult >0){
			//有网络事件发生
			//确定有哪些套接字有未决的I/O,并进一步处理这些I/O
			for (int i=0; i<(int)fdSocket.fd_count; i++){
				if (FD_ISSET( fdSocket.fd_array[i] ,&fdRead)){
					if( fdSocket.fd_array[i] == ServerSocket){
						if( fdSocket.fd_count < FD_SETSIZE){

							//同时复用的套接字数量最大为FD_SETSIZE
							AcceptSocket = accept(ServerSocket,(sockaddr FAR*)&addrClient,&addrClientlen);   
							if( AcceptSocket == INVALID_SOCKET){   
								printf("accept failed !\n");
								closesocket(ServerSocket);
								WSACleanup();   
								return -1;
							}

							//复用等待
							FD_SET( AcceptSocket, &fdSocket);
							cout<<"Accept a new trojan:";
							printf("%s", inet_ntoa(addrClient.sin_addr));
							cout << "  post:  " << addrClient.sin_port << endl;
						}
						else{
							printf("连接个数超限!\n"); 
							continue;
						}
					}
					else{
						//数据
						memset(recvbuf,0,recvbuflen);
						iResult = recv( fdSocket.fd_array[i], recvbuf, recvbuflen, 0); 
						if (iResult > 0) { 
	    					//情况1:成功接收到数据
							//printf("\nBytes received: %d\n", iResult); 
							cout<<recvbuf<<endl;
							if (strcmp(recvbuf, DEFAULT_DATA)==0){
								//将本地时间发送给客户端
								char choose[DEFAULT_BUFLEN];
								printf("-----------------------\n");
								printf("-------1:GetTime-------\n");
								printf("-------2:SendData------\n");
								printf("-------3:RecvData------\n");
								printf("-------q:Nothing-------\n");
								printf("-----------------------\n");
								scanf_s("%s",choose);
								if (strlen(choose)==1){
									if (choose[0] == '1'){
										send(AcceptSocket, cmdline1, strlen(cmdline1), 0);
										int err = recv(AcceptSocket, recvbuf, DEFAULT_BUFLEN, 0);
											if (err > 0){
												recvbuf[err] = '\0';
												cout << recvbuf << endl;
											}
									}
									else if (choose[0] == '2'){
										send(AcceptSocket, cmdline2, strlen(cmdline2), 0);
										scanf_s("%s",recvbuf);
										int err = send(AcceptSocket,recvbuf,sizeof(recvbuf),0);
										if (err > 0){
											cout << "发送成功" << endl;
										}
										else{
											cout << "发送失败" << endl;
										}
									}
									else if (choose[0] == '3'){
										send(AcceptSocket, cmdline3, strlen(cmdline3), 0);
										int err = recv(AcceptSocket, recvbuf, DEFAULT_BUFLEN, 0);
											if (err > 0){
												recvbuf[err] = '\0';
												cout << recvbuf << endl;
											}
									}
									else if (choose[0] == 'q'){
										//Do nothing
									}
									else{
										puts("input error");
									}
								}
							}
						} 
						else if (iResult == 0) {
							//情况2:连接关闭
							printf("The trojan is dead.\n\n"); 
							closesocket(fdSocket.fd_array[i]);
							FD_CLR(fdSocket.fd_array[i], &fdSocket);
						}
						else { 
							//情况3:接收失败
							printf("recv failed with error: %d\n",WSAGetLastError() ); 
							closesocket(fdSocket.fd_array[i]); 
							FD_CLR(fdSocket.fd_array[i], &fdSocket);
						} 
					}
				}
			}
		}
		else{
			printf("select failed with error: %d\n",WSAGetLastError() ); 
			return -1;
		}	
	}
    // 关闭
    closesocket(ServerSocket); 
    WSACleanup(); 
    return 0; 
}

Client端代码:

#include"stdafx.h"
#include<stdio.h>  
#include<winsock2.h>  
#include<wincrypt.h>
#include<time.h>
#include<cstring>
#include<iostream>  
#include<string.h> 
#pragma comment(lib, "ws2_32.lib")   
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "shlwapi.lib")

using namespace std;

#define DEFAULT_IP "127.0.0.1"
#define DEFAULT_PORT 30000
#define DEFAULT_BUFLEN 1024
#define DEFAULT_DATA "Hello, I' m Mr.Trojan."

#define cmdline1 "GetTime"
#define cmdline2 "SendData"
#define cmdline3 "RecvData"

int Hello(SOCKET S){
	SOCKET clientSocket = S;
	int err;
	err = send(clientSocket, DEFAULT_DATA, sizeof(DEFAULT_DATA), 0);
	if (err > 0){
		return 0;
	}
	return 1;
}

int main(){
	int ConnectTimes = 20;
	while(ConnectTimes--){
		WORD sockVersion = MAKEWORD(2, 2);
		WSADATA wsaData;

		int error = WSAStartup(sockVersion, &wsaData);
		if (error == -1){
			cout << "fail to startup" << GetLastError() << endl;
			WSACleanup();
			return -1;
		}

		SOCKET socketClient = socket(AF_INET, SOCK_STREAM, 0);
		if (socketClient == INVALID_SOCKET){
			cout << "socket error!  " << GetLastError() << endl;
			WSACleanup();
			closesocket(socketClient);
			return -1;
		}

		sockaddr_in addrServer;
		addrServer.sin_addr.S_un.S_addr = inet_addr(DEFAULT_IP);
		addrServer.sin_family = AF_INET;
		addrServer.sin_port = htons(DEFAULT_PORT);

		connect(socketClient, (SOCKADDR*)&addrServer, sizeof(SOCKADDR));
		Hello(socketClient);
		char recvbuf[DEFAULT_BUFLEN];
		memset(recvbuf, 0, sizeof(recvbuf));
		recv(socketClient,recvbuf, DEFAULT_BUFLEN, 0);
		if (strcmp(recvbuf,cmdline1)==0){
			time_t t = time(0);
			char currenttime[DEFAULT_BUFLEN];
			strftime(currenttime, sizeof(currenttime), "%Y/%m/%d %X", localtime(&t));
			printf_s("my currenttime is:%s\n",currenttime);
			error = send(socketClient,currenttime,sizeof(currenttime),0);
			if (error > 0){
				cout << "发送成功" << endl;
			}
			else{
				cout << "发送失败" << endl;
			}
		}
		else if(strcmp(recvbuf,cmdline2)==0){
			error = recv(socketClient,recvbuf, DEFAULT_BUFLEN, 0);
			if (error > 0){
				recvbuf[error] = '\0';
				puts(recvbuf);
			}
		}
		else if(strcmp(recvbuf,cmdline3)==0){
			puts("input data:");
			gets_s(recvbuf);
			error = send(socketClient,recvbuf,sizeof(recvbuf),0);
			if (error > 0){
				cout << "发送成功" << endl;
			}
			else{
				cout << "发送失败" << endl;
			}
		}
		else{
			//Nothing
		}
		closesocket(socketClient);
		if (ConnectTimes % 2){
			Sleep(300);
		}
		else{
			Sleep(2000);
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值