Windows平台的TCP服务端客户端

实现基于TCP的服务端与客户端

  • 服务端
//TestTcpServer.h
#include "winsock2.h" //引用头文件
#pragma comment (lib,"ws2_32.lib") //链接库文件
#include<Windows.h>
#include "Server.h"
#include <iostream>
#define MAX_TCP_BUF_LEN 1024
#define TCP_SERVER_PORT 10500
#define IP_ADDR "10.120.182.149"
#define MAX_CLIENT_NUM 3

// TestTcpServer.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。



#include "TestTcpServer.h"

int main()
{

	std::cout << "Welcome!\n";

	HANDLE hThread;
	DWORD  threadId;

	hThread = CreateThread(NULL,0, Tcp_Server_Function,0,0,&threadId);

	//1.初始化socket,并监听端口


	//2.创建线程

 
}


//server.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
DWORD WINAPI Tcp_Server_Function(LPVOID p);

//server.cpp
#define  _WINSOCK_DEPRECATED_NO_WARNINGS
#include "TestTcpServer.h"
#include "Server.h"


DWORD WINAPI Tcp_Server_Function(LPVOID p)
{
	std::cout << "Tcp_Server_Start ,pid = "<< GetCurrentThreadId() << std::endl;
	int ret = 0;
	WSADATA wsd;
	if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
	{
		WSACleanup();
		return -1;
	}; //初始化套接字

	int serverSocketFd = 0;
	serverSocketFd = socket(AF_INET, SOCK_STREAM, 0);
	if (serverSocketFd == INVALID_SOCKET)
	{
		std::cout << "creat socket fail ,error num = !" << WSAGetLastError() << std::endl;
		WSACleanup();
		return -1;
	}
	sockaddr_in local_addr;
	sockaddr_in remote_addr;
	memset(&local_addr, 0x0, sizeof(sockaddr_in));
	memset(&remote_addr, 0x0, sizeof(sockaddr_in));

	local_addr.sin_addr.S_un.S_addr = inet_addr("10.120.182.149");


	local_addr.sin_family = AF_INET;
	local_addr.sin_port = TCP_SERVER_PORT;

	int addrlen_ = sizeof(local_addr);
	//绑定套接字描述符和指定的ip 端口
	if (bind(serverSocketFd, (sockaddr*)&local_addr, addrlen_) == SOCKET_ERROR)
	{
		std::cout << "creat socket fail ,error num = !" << WSAGetLastError() << std::endl;
		closesocket(serverSocketFd);
		WSACleanup();
		return -1;
	}

	if (SOCKET_ERROR == listen(serverSocketFd, MAX_CLIENT_NUM))
	{
		std::cout << "creat socket fail ,error num = !" << WSAGetLastError() << std::endl;
		closesocket(serverSocketFd);
		WSACleanup();
		return -1;
	}
	SOCKET client;
	while (1)
	{
		std::cout << "等待客户端连接" << std::endl;
		client = accept(serverSocketFd, (sockaddr*) &remote_addr, &addrlen_);
		if(INVALID_SOCKET == client)
		{
			std::cout << "creat socket fail ,error num = !" << WSAGetLastError() << std::endl;
			//closesocket(client);
			closesocket(serverSocketFd);
			WSACleanup();
		}
		else
		{
			std::cout << "Client connectted!" << std::endl;
			char *msg = (char *)"hello";
			send(client, msg, 6, 0);
			char buff[MAX_TCP_BUF_LEN] = { 0 };
			int buff_len = recv(client, buff, 100, 0);
			if (buff_len > 0)
			{
				std::cout << "来自客户端发过来的消息:"<<buff << std::endl;
			}
			break;
		}


	}
	closesocket(serverSocketFd);
	WSACleanup();

	system("pause");
	return  0;
}


  • 客户端
// yxs.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#define _WINSOCK_DEPRECATED_NO_WARNINGS

/*头文件包含*/
#include "yxs.h"
#include <iostream>
#include <WinSock2.h> // windows下的socket相关的库
#include <stdio.h>  
#include <errno.h>
#include <sys/types.h>

#define MAX_RECVBUF_LENTH 1024*4
#define SERVER_IP "47.97.181.98"
#define SERVER_PORT 20000

#pragma comment(lib,"ws2_32.lib") 

using namespace std;


int main(int argc, char* argv[])
{
    char recvbuf[MAX_RECVBUF_LENTH] = { 0 };

    //0.初始化WSA ,windows平台才有
    WORD sockVersion = MAKEWORD(2, 2);
    WSADATA wsaData;
    if (WSAStartup(sockVersion, &wsaData) != 0)
    {
        return -1;
    }
    //创建socket
    SOCKET client_socket = socket(AF_INET, SOCK_STREAM ,0);
    if (INVALID_SOCKET == client_socket)
    {
        cout << "creat socket failed! " << endl;
        return -1;
    }
    //将socket设置为非阻塞
    int argp = 1;
    if (NO_ERROR != ioctlsocket(client_socket, FIONBIO, (u_long FAR*) &argp))
    {
        cout << "set nonblock socket failed!" << endl;
        return -1;
    }
    
    //设置服务器的addr
    sockaddr_in server_addr;
    memset(&server_addr, 0x0, sizeof(sockaddr_in));

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);
    server_addr.sin_addr.S_un.S_addr = inet_addr(SERVER_IP);

    //客户端不需要bind listen accept,直接connect建立连接
   
    for(;;) 
    {
        int ret_connect = connect(client_socket, (sockaddr*)&server_addr, sizeof(server_addr));
        cout << "ret_connect = " << ret_connect << endl;
		int errnom = 0;
		errnom = WSAGetLastError();
        if (0 == ret_connect)
        {
            cout << "connect successful!" << endl;
            break;
        }
        
        else if (-1 == ret_connect )
        {
            if (WSAEWOULDBLOCK== errnom)
            {
                break;
            }
					
			else if (WSAEINPROGRESS == errnom)
			{
				//连接中  
				continue;
			}
            else 
            {
                //连接出错
                closesocket(client_socket);
                WSACleanup();
                cout << "connect erro!" << endl;
                break;
            }
        }
     }
    int result = 0;
    timeval my_outtime;

    int count = 0;
    while(TRUE)
    {
        fd_set t_set;
        FD_ZERO(&t_set);
        FD_SET(client_socket, &t_set);
        my_outtime.tv_sec = 1;
        my_outtime.tv_usec = 0;
        result = select(client_socket + 1, &t_set,NULL,NULL, &my_outtime);  //这里需要注意的是,非阻塞的socket如果最后的参数设置为NULL,当当前socket没有可读事件时,就会一直阻塞。
        //需要注意的是,如果设置my_outtime的tv_sec和tv_usec都是0且作为传参的话,意思是不等待,如果没有事件立马返回,与传NULL是不一样的
        count++;
        //cout << "count = " << count << endl;
        //Sleep(1000);
        if (-1 == result)
        {
            if (EINTR != errno)
            {
                cout << "select error ,errno = " << errno << endl;
                break;
            }
        }
        else if (0 == result)
        {
            cout << "out of time ,nothing in fd !" << endl;
            return 0;  //这里代表数据已经接收完了
        }
        else
        {   
            memset(&recvbuf, 0x0, sizeof(recvbuf));
            int  ret = recv(client_socket, recvbuf, MAX_RECVBUF_LENTH, 0);
            if (ret < 0)
            {
                cout << "recv data erro " << endl;
                closesocket(client_socket);
                return -1;
            }
            cout << "recv buf from server:" << recvbuf << endl;
            continue ;
        }
    }

    return 0;

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值