流式套接字程序设计

内容

基于流式套接字的C/S通信程序,程序要求:客户端与服务器建立连接之后,客户端向服务器发送一个简单的四则算式(只含一个算符),服务器收到这个算式后,对其进行计算,并将计算结果回送给客户端,客户端将计算结果显示出来。。

服务端

加载listen_socket服务: SOCKET listen_socket;

构建 listen_socket 对象:  listen_socket = socket(FA_INET,SOCK_STREAM,0);

绑定 sockaddr_in server_local;

 // INADDR_ANY 表示0.0.0.0 可监听本地多个ip地址 可以运行在不同机器不用硬编码

 //  htonl()将32为无符号数从主机字节序转换为网络字节序(多字节字符存储方式可能为大端或者小端,这里可以统一处理,增加程序的健壮性,可运行于不同机器)
       server_local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);  
       server_local.sin_port = htons(6000);                                     //绑定服务器监听端口
       server_local.sin_family = AF_INET;

       bind(listen_socket,(SOCKADDR*)&server_local,sizeof(server_local));

侦听 listen(server_local,5)                   //5表示 等待连接队列的最大长度

接受客户端连接请求、产生另一个work_socket对象与客户端通信

    sockaddr_in from;
    SOCKET client;
    int fromlen = sizeof(from);

    client =  accept(listen_socket,(SOCKADDR*)&from,&fromlen);

接收与发送

send(client,(char*)send_buffer,strlen(send_buffer),0);

recv(client,(char*)recv_buffer,strlen(recv_buffer),0)

关闭socket

shutdown(client_socket,SD_RECRIVE|SD_SEND|SEND_BOTH); //中断连接释放套接字资源

注销socket服务

closesocket(client);//关闭socket

客户端

加载socket服务 SOCKET client;

构建socket对象 client  = socket(AF_INET,SOCK_STREAM,0);

绑定服务器IP并connect 服务

    sockaddr_in server_addr;
    server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //将字符串转为长整形IP地址
    server_addr.sin_port = htons(6000);  //htons :host to network short
    server_addr.sin_family = AF_INET;

   connect(client,(SOCKADDR*)&server_addr, sizeof(server_addr));

接收与发送

recv send第二个参数均为char *

recv(client, recv_buffer, sizeof(recv_buffer),0);

send(client,send_buffer, sizeof(send_buffer),0); 

关闭socket

shutdown(client,SD_BOTH);

注销socket服务

closesocket(client);

源代码

IDE  VS2015

项目结构

165037_Bnkj_3166429.png

init:

//InitSock.h
#pragma once
#include "winsock2.h"
class CInitSock
{
public:
	CInitSock();
	~CInitSock();
};


//InitSock.cpp
#include "stdafx.h"
#include "InitSock.h"

CInitSock::CInitSock()
{
	WSADATA  wsaData;
	WORD socket_version = MAKEWORD(2,2);
	if (::WSAStartup(socket_version,&wsaData)!=0)
	{
		exit(0);
	}
}

CInitSock::~CInitSock()
{
	::WSACleanup();
}

服务端客户端 设计的运算结构体

​//Arithmetic.h
#pragma once
typedef struct arithmetic
{
	char _operator;  //+ - * /
	int data_1;   //操作数1
	int data_2;   //操作数2
} Arithmetic;

[点击并拖拽以移动]
​

server:

// server.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "conio.h"
#include "InitSock.h" //管理WinSock库 WSAStartup() WSACleanup完成初始化及回收。。
#include "iostream"
#include "Windows.h"   //线程
#include "Arithmetic.h"
#pragma comment(lib,"ws2_32.lib")//静态导入win32库

//服务器线程
DWORD WINAPI ServerThread(LPVOID pParam);
int main()
{
	int nRetCode = 0;
	std::cout << "PRESS ESCAPE退出服务端程序\n";
	DWORD threadID;
	HANDLE hThread;
	hThread = CreateThread(NULL, 0, ServerThread, NULL, 0, &threadID); // 创建线程  
	//WaitForSingleObject(hThread, INFINITE);
	//CloseHandle(hThread);   // 关闭内核对象  
	//AfxBeginThread(ServerThread, 0);
	while (_getch() != 27);
	return nRetCode;
}

DWORD WINAPI ServerThread(LPVOID pParam)
{
	std::cout << "启动TCP服务器初始化。。。\n";
	CInitSock cInitSock;

	//填充sockaddr_in
	sockaddr_in server_local;
	server_local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	server_local.sin_port = htons(6000);
	server_local.sin_family = AF_INET;

	SOCKET listen_socket = socket(AF_INET, SOCK_STREAM, 0);//创建TCP Socket
	if (INVALID_SOCKET == listen_socket)
	{
		std::cout << "创建服务器失败 \n";
		return 0;
	}

	//bind
	if (0 != bind(listen_socket, (SOCKADDR *)&server_local, sizeof(server_local)))
	{
		std::cout << "服务器绑定失败 \n";
		return 0;
	}

	//listen
	if (0 != listen(listen_socket, 5))
	{
		std::cout << "listen failure \n";
		return 0;
	}

	//accept
	sockaddr_in from;
	SOCKET client;
	int fromlen = sizeof(from);
	char buffer[1024] = { 0 };
	while (true)
	{
		client = accept(listen_socket, (SOCKADDR *)&from, &fromlen);
		if (client == INVALID_SOCKET);
		{
			std::cout << "Failed Accept \n";
		}
		sprintf(buffer, "hello client from server : \n", inet_ntoa(from.sin_addr));
		send(client, buffer, strlen(buffer), 0);
		std::cout << "Connection from " << inet_ntoa(from.sin_addr) << "\n";
		Arithmetic arithmetic;
		recv(client, (char*)&arithmetic, sizeof(arithmetic), 0);
		printf("%receive expression: %d %c %d = ? from client\n", arithmetic.data_1, arithmetic._operator, arithmetic.data_2);
		//计算结果
		int ans = 0;
		switch (arithmetic._operator)
		{
		case '+':
			ans = arithmetic.data_1 + arithmetic.data_2;
			break;
		case '-':
			ans = arithmetic.data_1 - arithmetic.data_2;
			break;
		case '*':
			ans = arithmetic.data_1 * arithmetic.data_2;
			break;
		case '/':
			ans = arithmetic.data_1 / arithmetic.data_2;
			break;
		default:
			break;
		}
		memset(buffer, 0, sizeof(buffer));
		printf("send answer = %d to client\n", ans);
		buffer[strlen(buffer)] = '\0';
		send(client, (char*)&ans, sizeof(ans),0);
		//close clientsocket
		shutdown(client, SD_BOTH);
		closesocket(client);
	}
	shutdown(listen_socket, SD_BOTH);
	closesocket(listen_socket);
	return 0;
}

客户端设计:

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

#include "stdafx.h"
#include "InitSock.h"
#include "iostream"
#include "conio.h"
#include "Windows.h"
#include "Arithmetic.h"
#pragma comment(lib,"ws2_32.lib")//静态导入win32库

DWORD WINAPI ClientThread(LPVOID pParam);
int main()
{
	int nRetCode = 0;
	Sleep(5000);
	std::cout << "PRESS ESCAPE退出客户端程序\n";
	DWORD threadID;
	HANDLE hThread;
	hThread = CreateThread(NULL, 0, ClientThread, NULL, 0, &threadID); // 创建线程 
	while (_getch() != 27);
	return nRetCode;
}

DWORD WINAPI ClientThread(LPVOID pParam)
{
	CInitSock cInitSock;
	SOCKET client = socket(AF_INET, SOCK_STREAM, 0);

	sockaddr_in server_addr;
	server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	server_addr.sin_port = htons(6000);
	server_addr.sin_family = AF_INET;
	printf("客户端已经启动\r\n");
	int conn;
	conn = connect(client, (SOCKADDR*)&server_addr, sizeof(server_addr));
	if (conn!=0)
	{
		std::cout << _T("客户端发起连接失败\n");
		return 0;
	}

	char recv_buffer[1024];
	int nRecv = 0;
	nRecv = recv(client, recv_buffer, sizeof(recv_buffer),0);
	
	if (nRecv > 0)
	{
		recv_buffer[nRecv] = '\0';
		printf("接收到的数据:%s\n", recv_buffer);
		//std::cout << recv_buffer;
		memset(recv_buffer, 0, strlen(recv_buffer));
		Arithmetic arithmetic;
		arithmetic.data_1 = 1;
		arithmetic.data_2 = 1;
		arithmetic._operator = '+';
		printf("send expression: %d %c %d = ? to server\n", arithmetic.data_1, arithmetic._operator, arithmetic.data_2);
		send(client,(char*)&arithmetic, sizeof(arithmetic),0);
		memset(recv_buffer, 0, sizeof(recv_buffer));

		//接收四则运算结果
		int ans = 0;
		nRecv = recv(client, (char*)&ans, sizeof(ans),0);
		printf("receive answer = %d from server\n", ans);

	}
	shutdown(client, SD_BOTH);
	closesocket(client);
	system("pause");
	return 0;
}

结果

172449_bgxV_3166429.png

总结:

新建一个VS解决方案,分别添加Client和Server两个Win32控制台项目并设置为同时启动方式为2个项目同时启动,注意在客户端启动时先Sleep(5000),等待服务器启动完成然后connect服务端。在每个子项目的主线程中新建一个线程进行socket操作,方便在主线程中控制程序结束。

 

 

 

转载于:https://my.oschina.net/u/3166429/blog/918509

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验名称:程序设计 实验目的:通过实验学习并掌握的使用方法及其在网络通信中的应用。 实验内容: 1. 编写一个简单的客户端程序,连到指定的服务器,并向服务器发送一条消息。 2. 编写一个简单的服务器程序,监听指定的端口号,收客户端发送的消息,并将消息打印输出到控制台上。 3. 实现客户端和服务器之间的双向通信,即客户端可以向服务器发送消息,服务器也可以向客户端发送消息。 实验步骤: 1. 编写客户端程序 ```python import socket # 创建一个socket对象 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 指定服务器的IP地址和端口号 server_address = ('127.0.0.1', 8888) # 连到服务器 client_socket.connect(server_address) # 向服务器发送一条消息 message = 'Hello, Server!' client_socket.sendall(message.encode()) # 收服务器的响应并打印输出 data = client_socket.recv(1024) print('Received from server:', data.decode()) # 关闭连 client_socket.close() ``` 2. 编写服务器程序 ```python import socket # 创建一个socket对象 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 指定监听的端口号 server_address = ('127.0.0.1', 8888) server_socket.bind(server_address) # 开始监听连 server_socket.listen(1) print('Listening on', server_address) # 受客户端的连请求 client_socket, client_address = server_socket.accept() print('Connected by', client_address) # 收客户端发送的消息并打印输出 data = client_socket.recv(1024) print('Received from client:', data.decode()) # 向客户端发送一条消息 message = 'Hello, Client!' client_socket.sendall(message.encode()) # 关闭连 client_socket.close() server_socket.close() ``` 3. 实现客户端和服务器之间的双向通信 客户端程序: ```python import socket # 创建一个socket对象 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 指定服务器的IP地址和端口号 server_address = ('127.0.0.1', 8888) # 连到服务器 client_socket.connect(server_address) while True: # 从控制台输入消息并发送给服务器 message = input('Input message to server:') client_socket.sendall(message.encode()) # 收服务器的响应并打印输出 data = client_socket.recv(1024) print('Received from server:', data.decode()) # 关闭连 client_socket.close() ``` 服务器程序: ```python import socket # 创建一个socket对象 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 指定监听的端口号 server_address = ('127.0.0.1', 8888) server_socket.bind(server_address) # 开始监听连 server_socket.listen(1) print('Listening on', server_address) # 受客户端的连请求 client_socket, client_address = server_socket.accept() print('Connected by', client_address) while True: # 收客户端发送的消息并打印输出 data = client_socket.recv(1024) print('Received from client:', data.decode()) # 从控制台输入消息并发送给客户端 message = input('Input message to client:') client_socket.sendall(message.encode()) # 关闭连 client_socket.close() server_socket.close() ``` 实验结果: 经过实验,我们成功地编写了一个简单的程序,实现了客户端与服务器之间的单向和双向通信,并通过控制台输出了相应的消息。 实验结论: 是一种在网络上进行数据传输的工具,通过它可以在不同的计算机之间进行数据传输。我们可以使用套函数库来实现Socket连的建立、数据的传输等功能。在进行网络通信时,需要设置超时时间,避免出现因网络延迟等问题导致程序卡死的情况。通过实验,我们掌握了的使用方法及其在网络通信中的应用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值