WinSock TCP通信程序示例_

参考文献:杨传栋, 张焕远. Windows网络编程基础教程[M]. 清华大学出版社, 2015.P114




服务器端程序代码:

//stdafx.h
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>



// TODO: 在此处引用程序需要的其他头文件

//targetver.h
#pragma once

// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。

// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。

#include <SDKDDKVer.h>
//stdafx.cpp
// stdafx.cpp : 只包括标准包含文件的源文件
// server.pch 将作为预编译头
// stdafx.obj 将包含预编译类型信息

#include "stdafx.h"

// TODO: 在 STDAFX.H 中
// 引用任何所需的附加头文件,而不是在此文件中引用

server.cpp:

// server.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include "iostream"
#include "winsock2.h"
#define PORT 65432   //定义端口号常量  端口号范围是0~65535
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main(int argc, char **argv)
{
	/***定义相关的变量***/
	SOCKET sock_server,newsock; //定义保存监听套接字及已连接套接字的变量
	struct sockaddr_in addr;  //用于填写绑定地址的结构变量
	struct sockaddr_in  client_addr;//存放客户端地址的sockaddr_in结构变量
	char msgbuffer[256];//定义用于接收客户端发来信息的缓区
	char msg[] ="Connect succeed.this message comes from server! \n"; //发给客户端的信息
	/***初始化winsock2.DLL***/
	WSADATA wsaData;
	WORD wVersionRequested=MAKEWORD(2,2);  //生成版本号2.2
	if(WSAStartup(wVersionRequested,&wsaData)!=0)
	{
		 cout<<"加载winsock.dll失败!\n";
		 return 0;
	 }
	/***创建套接字***/
	if ((sock_server = socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR) 
	{
		cout<<"创建套接字失败!错误代码:"<<WSAGetLastError()<<endl;
		WSACleanup();
		return 0;
	}
	/***填写要绑定的本地地址***/
	int addr_len = sizeof(struct sockaddr_in);
	memset((void *)&addr,0,addr_len);  //将地址结构变量清0
	addr.sin_family =AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);//允许使用本机的任何IP地址



	/***给监听套接字绑定地址***/
	if(bind(sock_server,( struct sockaddr *)&addr,sizeof(addr))!=0)    
	{
		cout<<"地址绑定失败!错误代码:"<<WSAGetLastError()<<endl;
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}



	/***将套接字设为监听状态****/
	if(listen(sock_server,0)!=0)      
	{
		cout<<"listen函数调用失败!错误代码:"<<WSAGetLastError()<<endl;
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	else
		cout<<"listenning......\n"; 
	/***循环:接收连接请求并收发数据***/










	int size;
	while(true)
	{
		if((newsock = accept (sock_server, (struct sockaddr *)&client_addr, 
       &addr_len)) ==INVALID_SOCKET)
	   { 
			cout<<"accept函数调用失败!错误代码:"<<WSAGetLastError()<<endl;
			break; //终止循环
		}
		else
			cout<<"成功接收一个连接请求!\n";
		/***成功接收一个连接后先发送信息,再接收信息***/
		size=send(newsock,msg,sizeof(msg),0);//给客户端发送一段信息
        if(size== SOCKET_ERROR)
        {
			cout<<"发送信息失败!错误代码:"<<WSAGetLastError()<<endl;
			closesocket(newsock);//关闭已连接套接字
			continue;  //继续接收其他连接请求
        }
		else if(size==0)
		{
			cout<<"对方已关闭连接!\n";
			closesocket(newsock);//关闭已连接套接字
			continue; //继续接收其他连接请求
		}
		else
			cout<<"信息发送成功!\n";
		if((size=recv(newsock,msgbuffer,sizeof(msgbuffer),0))<0)//接收信息
		{
			cout<<"接收信息失败!错误代码:"<<WSAGetLastError()<<endl;
			closesocket(newsock);//关闭已连接套接字
			continue; //继续接收其他连接请求
		}
		else if(size==0)
		{
			cout<<"对方已关闭连接!\n";
			closesocket(newsock);//关闭已连接套接字
			continue; //继续接收其他连接请求
		}
		else
			cout<<"收到的信息为:"<<msgbuffer<<"共size个字节"<<size<<endl; 
		
		closesocket(newsock);   //通信完毕关闭“已连接套接字”
	}
		/***结束处理***/
	closesocket(sock_server);//关闭监听套接字
	WSACleanup();//注销WinSock动态链接库
	return 0;
}


客户端代码:

stdafx.h

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>



// TODO: 在此处引用程序需要的其他头文件

targetver.h

#pragma once

// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。

// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。

#include <SDKDDKVer.h>

stdafx.cpp

// stdafx.cpp : 只包括标准包含文件的源文件
// client.pch 将作为预编译头
// stdafx.obj 将包含预编译类型信息

#include "stdafx.h"

// TODO: 在 STDAFX.H 中
// 引用任何所需的附加头文件,而不是在此文件中引用

client.cpp

// client.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include "iostream"
#include "winsock2.h"
#define PORT 65432         //定义要访问的服务器端口常量
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main(int argc, char **argv)
{
	//struct in_addr inad1;
	//struct sockaddr_in sd1;
	//struct sockaddr sad2;
	//cout << "sizeof(in_addr)=" << sizeof(in_addr) << endl;
	//cout << "sizeof(sockaddr_in)=" << sizeof(sockaddr_in) << endl;
	//cout << "sizeof(sockaddr)=" << sizeof(sockaddr) << endl;



	/***定义相关的变量***/
	int sock_client;  //定义客户端套接字
	struct sockaddr_in server_addr; //定义存放服务器端地址的结构变量
	int addr_len = sizeof(struct sockaddr_in); //地址结构变量的内存字节大小
	char msgbuffer[1000]; //接收/发送信息的缓冲区
	/***初始化winsock DLL***/ 
	WSADATA wsaData;
	WORD wVersionRequested=MAKEWORD(2,2);  //生成版本号2.2
	if(WSAStartup(wVersionRequested,&wsaData)!=0)
	{
		cout<<"加载winsock.dll失败!\n";
		return 0;
	}
	/***创建套接字***/
	if ((sock_client = socket(AF_INET,SOCK_STREAM,0))<0) 
	{
		cout<<"创建套接字失败!错误代码:"<<WSAGetLastError()<<endl;
		WSACleanup();
		return 0;
	}
	/***填写服务器地址***/
	char IP[20]="127.0.0.1";
	//cout<<"请输入服务器IP地址:";//使用内网地址:192.168.2.116  或环回地址127.0.0.1
	//cin>>IP;

	memset((void *)&server_addr,0,addr_len);//地址结构清0,初始化为0

	//void *  __cdecl memset(_Out_writes_bytes_all_(_Size) void * _Dst, _In_ int _Val, _In_ size_t _Size);
	//memset(void *s,int ch,size_t n);//将s所指向的某一块内存中的后n个 字节的内容全部设置为ch指定的ASCII值, 第一个值为指定的内存地址,块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作, 其返回值为s。


	server_addr.sin_family =AF_INET;
	server_addr.sin_port = htons(PORT);
	server_addr.sin_addr.s_addr = inet_addr(IP);//填写服务器IP地址


	/*inet_addr:地址转换函数,
	WINSOCK_API_LINKAGE
	unsigned long
	WSAAPI
	inet_addr(
    _In_z_ const char FAR * cp
    );
	将cp所指的点分十进制字符串表示的IP地址转换为32位无符号长整型,网络字节顺序。

	*/

        /***与服务器建立连接***/
	if(connect(sock_client,(struct sockaddr *)&server_addr,addr_len)!=0)    
	{
		cout<<"连接失败!错误代码:"<<WSAGetLastError()<<endl;
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}


	获取与套接字关联的地址
	//int namelen;
	//struct sockaddr_in client_addr;
	//int n = getsockname(sock_client, (struct sockaddr*)&client_addr, &namelen);
	//if (n == SOCKET_ERROR)
	//{
	//	cout << "getsockname error!" << endl;
	//}
	//else
	//{
	//	cout << "本地套接字端口号:" << client_addr.sin_port << ",IP地址是:" << inet_ntoa(client_addr.sin_addr) << endl;
	//}



	/***接收信息并显示***/
	int size;
	if((size=recv(sock_client,msgbuffer,sizeof(msgbuffer),0))<0)
	{
		cout<<"接收信息失败!错误代码:"<<WSAGetLastError()<<endl;
		closesocket(sock_client);//关闭已连接套接字
		WSACleanup(); //注销WinSock动态链接库
		return 0;
	}
	else if (size == 0)
	{
		cout << "对方已关闭连接!\n";
		closesocket(sock_client);//关闭已连接套接字
		WSACleanup(); //注销WinSock动态链接库
		return 0;
	}
	else
		cout << "接受到的字节数:size=" << size << endl;
		cout<<"The message from Server: "<<msgbuffer<<endl; 



	/***从键盘输入一行文字发送给服务器***/
	cout<<"从键盘输入发给服务器的信息!\n";
	cin>>msgbuffer;
	cout << "sizeof(msgbuffer)=" << sizeof(msgbuffer) << endl;//sizeof(msgbuffer)=1000

	if((size=send(sock_client,msgbuffer,sizeof(msgbuffer),0))<0)
	cout<<"发送信息失败!错误代码:"<<WSAGetLastError()<<endl;
	else if(size==0)
	cout<<"对方已关闭连接!\n";
	else
	cout<<"信息发送成功!\n";
	/***结束处理***/
	closesocket(sock_client); //关闭socket
	WSACleanup(); //注销WinSock动态链接库





	获取与套接字关联的地址
	//int namelen;
	//struct sockaddr_in client_addr;
	//int n = getsockname(sock_client, (struct sockaddr*)&client_addr, &namelen);
	//if (n == SOCKET_ERROR)
	//{
	//	cout << "getsockname error!" << endl;
	//}
	//else
	//{
	//	cout << "本地套接字端口号:" << client_addr.sin_port << ",IP地址是:" << inet_ntoa(client_addr.sin_addr) << endl;
	//}

	///*
	//#if INCL_WINSOCK_API_PROTOTYPES
	//_WINSOCK_DEPRECATED_BY("inet_ntop() or InetNtop()")
	//WINSOCK_API_LINKAGE
	//char FAR *
	//WSAAPI
	//inet_ntoa(
	//_In_ struct in_addr in
	//);
	//#endif // INCL_WINSOCK_API_PROTOTYPES

	//chat* inet_ntoa(struct in_addr in);
	//in:是一个保存有32位IP地址的二进制IP地址的in_addr结构变量

	//函数功能:将一个保存在in_addr结构变量中的长整型IP地址转换为点分十进制字符串形式。
	//*/


	//int serverNameLen;
	//struct sockaddr_in server_addr2;
	//int servern = getpeername(sock_client, (struct sockaddr*)&client_addr, &serverNameLen);

	//if (servern == SOCKET_ERROR)
	//{
	//	cout << "getsockname error!" << endl;
	//}
	//else
	//{
	//	cout << "本地套接字端口号:" << server_addr2.sin_port << ",IP地址是:" << inet_ntoa(server_addr2.sin_addr) << endl;
	//}

	system("pause");
	return 0;
}










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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值