一个简单的TCP通信程序

1.基本通信过程
(1)调用socket()函数建立一个套接字,用于监听
(2)调用bind()函数为套接字绑定一个端口号,IP地址
(3)listen()函数,设置套接字处于监听状态
(4)若程序不退出,则反复执行
1)accept()函数等待客户机的连接。若远程计算机连接请求到来,则一个新的套接字与客户机直接的通信连接
2)rev(),send()利用新建连接与客户机通信
3)通信完 ,调用closesocket()函数关闭连接
(5)closesocket()关闭监听套接字,程序结束。

重点:!!!!!!8个常用函数的定义
(1)创建套接字
函数原型
SOCKET socket(int af,int type,int protocol);
af:地址家族 IPV4协议 AF_INET
type:标识套接字类型,SOCK STREAM流式套接字; SOCKET_DGREAM数据报套接字
protocol:传输的协议,与type有关,取0,代表默认的协议
如果套接字出错,返回INVALID_SOCKET.
eg1://创建一个套接字

SOCKET sock_server;//sock_server变量
if((sock_server=socket(AF_INET,SOCK_STREAM,0))==INVALID SOCKET)
{
std::cout<<"创建套接字失败!错误代码:<<WSAGetLastError()<<std::endl;
WSACleanup();
return 0;

(2)绑定地址
//将套接字绑定到一个指定的地址上的套接字函数是bind()
函数原型
int bind(SOCKET s,const sockaddr * name,int namelen);
s是一个套接字
name是sockaddr结构指针,包含绑定的地址,端口i应该。该类型已经被定义为LPSOCKADDR:
typedef sockaddr *LPSOCKADDR;

//套接字绑定地址的典型方式
#define PORT 65432//指定本程序监听的TCP端口号
...
struct sockaddr_in addr;//定义sockaddr_in结构变量addr
memset((void*)&addr,0,addr_len)://addr各字段值全部置为0
addr.sin_family=AF_INET;//协议族为AF_INET
addr.sin_port=htons(PORT);//端口常量PORT,PORT自己设置值
addr.sin_addr.s_addr=htonl(INADDR_ANY);//监听本机分配的所有IP地址
if(bind(sock_server,(struct sockaddr *)&addr,sizeof(addr))!=0)//绑定地址
{
std::cout<<"绑定失败!错误代码:"<<WSAGetLastError()<<std::endl;
closesocket(sock_server)//关闭套接字
WSACleanp();
return 0;
}
(3)开始监听
函数原型
int listen(SOCKET s,int backlog)//只能是服务器端的函数,适用于流式套接字4)建立连接
函数原型
1)建立客户端和服务器端的连接。客户端调用connect()发起主动连接
int connect(SOCKET s,const struct sockaddr *name,int namelen);
2)服务器端调用accept()函数
SOCKET accept(SOCKET s,struct sockaddr * addr,int FAR * addrlen)
(5)发送和接收数据
1)发送数据send()函数
int send(SOCKET S,const char *buf,int len,int flags);
2)接收数据rev()函数
int recv(SOCKET s,char *buf ,int len, int flags);
(6)关闭套接字
函数原型
int closesocket(SOCKET s);
(7)获取套接字绑定的IP地址和端口号
函数原型
int getsockname(SOCKET s,struct sockaddr *name,int * namelen);8)获取与本地套接字相连的对端套接字协议地址,用 getpeername()函数
int getpeername(SOCKET s,struct sockaddr FAR *name,int FAR *namelen)


2.客户端
(1)socket()函数建一个套接字,设服务器IP端口
(2)调connect()函数连接远程计算机指定端口
(3)recv()函数,send()函数利用新建连接与服务器通信
(4)通信完 ,调closesocket()关闭连接
在这里插入图片描述

// ConsoleApplication4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//客户端
#include <iostream>
#include "winsock2.h"
#define PORT 65432
#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;//定义用于接收客户端发来信息的缓冲区
	char msgbuffer[256];//定义用于接收客户端发来消息的缓冲区
	char msg[] = "connect succeed.\n";//发给客户端的消息
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &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);//地址结构变量清零
	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 << "listening····\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, strlen(msg) + 1, 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 << endl;
		closesocket(newsock);
	}
	closesocket(sock_server);
	WSACleanup();
	return 0;

}

3.服务器

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

#include <iostream>
#include "winsock2.h"
#include "WS2tcpip.h"//本机用地址转换话术inet_pton(),包含头文件
#define PORT 65432
#pragma comment(lib,"ws2_32.lib")
using namespace std;

int main(int argc,char ** argv)
{
   /*定义相关变量*/
	int sock_client;//定义客户端套接字
	struct sockaddr_in server_addr;//定义存放服务器端地址的结构变量
	int addr_len = sizeof(struct sockaddr_in);//地址结构变量长度
	char msgbuffer[1000];//接送和发送信息的缓冲区
	/*初始化winsock2.ddl*/
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		cout << "加载winsock.dll失败!\n";
		return 0;
	}
	/*创建套接字*/
	if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
	{
		cout << "创建套接字失败。错误代码是:" << WSAGetLastError() << endl;
		WSACleanup;
		return 0;
	}
	/*输入服务器IP地址并且填写服务器地址结构*/
	char IP[20];
	cout << "请输入服务器IP地址";
	cin >> IP;
	memset((void *)&server_addr, 0, addr_len);
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(PORT);
	in_addr a;
	inet_pton(AF_INET, IP, &a);//?
	server_addr.sin_addr.s_addr = a.S_un.S_addr;//服务器IP地址
	/*与服务器建立连接*/
	if (connect(sock_client, (struct sockaddr*)&server_addr, addr_len) != 0)
	{
		cout << "connect fail;error code:" << WSAGetLastError() << endl;
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}
	/*接收信息并显示*/
	int size;
	if ((size = recv(sock_client, msgbuffer, sizeof(msgbuffer), 0)) < 0)
	{
		cout << "recieve message failed.error code:" << WSAGetLastError() << endl;
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}
	else if (size == 0)
	{
		cout << "对方已关闭连接!\n";
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}
	else
		cout << "the message from server:" << msgbuffer << endl;
	/*从键盘输入发给服务器的信息*/
	cout << "从键盘输入发给服务器的信息\n";
	cin >> msgbuffer;
	if ((size = send(sock_client, msgbuffer, strlen(msgbuffer) + 1, 0)) < 0)
		cout << "发送信息失败!错误代码:" << WSAGetLastError() << endl;
	else if (size == 0)
		cout << "对方已关闭连接!\n";
	closesocket(sock_client);
	WSACleanup();
	return 0;
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于Modbus TCP通信程序,我可以帮助您解决问题。您需要具备一些基本的编程知识,了解TCP/IP协议和Modbus协议。以下是一个模拟Modbus TCP主机和从机进行通信的示例代码: ```python import socket def modbus_read_input_registers(ip_addr, port, unit_id, address, count): # 建立TCP连接 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip_addr, port)) # 准备Modbus请求报文 transaction_id = 0 # 事务ID protocol_id = 0 # 协议标识 length = 6 # 报文长度 slave_address = unit_id # 从机地址 function_code = 4 # 功能码,读取输入寄存器 start_address = address # 起始地址 register_count = count # 寄存器数量 request = struct.pack('>HHHBBHH', transaction_id, protocol_id, length, slave_address, function_code, start_address, register_count) # 发送Modbus请求报文 sock.send(request) # 接收Modbus响应报文 response = sock.recv(1024) # 解析Modbus响应报文 data = response[9:] # 数据段 values = struct.unpack('>' + 'H' * (len(data) // 2), data) # 每个寄存器的值 sock.close() return values ``` 这段代码实现了读取Modbus从机的输入寄存器的功能。您需要传递从机的IP地址、端口、从机地址、起始地址和寄存器数量作为参数。该函数将返回一个元组,其中包含请求的寄存器值。 关于如何编写Modbus TCP通信程序,您需要根据具体的需求和设备类型进行调整。但上述代码可以作为参考,并且大多数Modbus TCP设备都支持标准的Modbus读写功能代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值