window套接字编程

套接字

什么是套接字?套接字(socket)是操作系统提供的用来进行网络数据传输的软件设备。即使对网路数据传输原理不太熟悉,也可以通过套接字完成数据传输。

操作系统提供相应的函数,windows和linux提供的函数有一些差异,但大致思想是一样的。下面介绍windows的几个函数:

socket函数创建套接字:

SOCKET socket(int af, int type, int protocol);

成功时返回套接字句柄,失败时返回INVALID_SOCKET。句柄其实就是标识符,唯一地标识某个东西。

bind函数为套接字分配IP地址和端口号:

int bind(SOCKET s, const struct sockaddr *name, int namelen);

成功时返回0,失败时返回SOCKET_ERROR。

listen函数使套接字可接受客户端连接,即将套接字转换成可接收连接的状态:

int listen(SOCKET s, int backlog);

成功时返回0,失败时返回SOCKET_ERROR。

accept函数使套接字处理客户端连接请求:

SOCKET accept(SOCKET s, struct sockaddr *addr, int *addrlen);

成功时返回套接字句柄,失败时返回INVALID_SOCKET。

connect函数从客户端发送请求:

int connect(SOCKET s, const struct sockaddr *name, int namelen);

成功时返回0,失败时返回SOCKET_ERROR。

send函数:

int send(SOCKET s, const char *buf, int len, int flags);

成功时返回传输字节数,失败时返回SOCKET_ERROR。s表示数据传输对象连接的套接字句柄值,buf保存待传输数据的缓冲地址值,len表示要传输的字节数,flags为传输数据时用到的多种选项信息。

recv函数:

int recv(SOCKET s, const char *buf, int len, int flags);

成功时返回接收到的字节数,失败时返回SOCKET_ERROR。参数表示含义和send类似。

服务端的一般步骤是:

(1)调用socket函数创建套接字。

(2)调用bind函数分配IP地址和端口号。

(3)调用listen函数转换为可接收请求状态。

(4)调用accept函数受理连接请求。

客户端的一般步骤是:

(1)调用socket函数创建套接字。

(2)调用connect函数向服务端发送连接请求。

环境配置

windows下套接字编程需要用到头文件WinSock2.h,以及链接ws2_32.lib库。

vs中链接ws2_32.lib库的方法:进入项目属性--》输入--》附加依赖项 直接写入ws2_32.lib。



windows下套接字编程

Winsock其实就是Windows Socket的简称,即Windows套接字。

进行Winsock编程时,首先必须调用WSAStartup函数,设置程序中用到的Winsock版本,并初始化相应版本的库。

int WSAStartup(WORD mVersionRequested, LPWSADATA lpWSAData);

Winsock存在多个版本,应准备WORD类型的套接字版本信息,传递给函数的第一个参数。WORD是通过typedef声明定义的unsigned short类型。可以借助MAKEWORD宏函数构建WORD型的版本信息,如MAKEWORD(1,2)返回的是0x0201,表示版本号1.2,MAKEWORD(2,2)返回的是0x0202,表示版本号2.2。

第二个参数传入WSADATA型结构体变量地址(LPWSADATA是WSADATA的指针类型)。调用完函数后,相应参数中将填充已初始化的库信息。

现在给一个小例子,服务段向客户端返回Hello World!。

服务器端代码:

#include<iostream>
#include<cstdio>
#include<WinSock2.h>
using namespace std;

void errorHandling(char *message);

int main()
{
	WSADATA wsaData;
	SOCKET serverSock, clientSock;
	SOCKADDR_IN serverAddr, clientAddr;
	int szClientAddr, port;
	char message[] = "Hello World!";
	cout << "输入端口号:";
	cin >> port;

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		errorHandling("WSAStartup() error");

	serverSock = socket(PF_INET, SOCK_STREAM, 0);
	if (serverSock == INVALID_SOCKET)
		errorHandling("socket() error");

	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	serverAddr.sin_port = htons(port);

	if (bind(serverSock, (SOCKADDR *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
		errorHandling("bind() error");

	if (listen(serverSock, 5) == SOCKET_ERROR)
		errorHandling("listen() error");

	szClientAddr = sizeof(clientAddr);
	clientSock = accept(serverSock, (SOCKADDR *)&clientAddr, &szClientAddr);
	if (clientSock == INVALID_SOCKET)
		errorHandling("accept() error");

	send(clientSock, message, sizeof(message), 0);
	closesocket(clientSock);
	closesocket(serverSock);
	WSACleanup();

	return 0;
}

void errorHandling(char *message)
{
	cerr << message << endl;
	exit(1);
}

客户端代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<WinSock2.h>
using namespace std;

void errorHandling(char *message);

int main()
{
	WSADATA wsaData;
	SOCKET mySocket;
	SOCKADDR_IN serverAddr;
	char message[30], ip[20];
	int strlen, port;

	cout << "输入ip:";
	cin >> ip;
	cout << "输入端口号:";
	cin >> port;

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		errorHandling("WSAStartup() error");

	mySocket = socket(PF_INET, SOCK_STREAM, 0);
	if (mySocket == INVALID_SOCKET)
		errorHandling("socket() error");

	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = inet_addr(ip);
	serverAddr.sin_port = htons(port);

	if (connect(mySocket, (SOCKADDR *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
		errorHandling("connect() error");

	strlen = recv(mySocket, message, sizeof(message) - 1, 0);
	if (strlen == -1) errorHandling("read() error");
	printf("Message from server:%s\n", message);

	closesocket(mySocket);
	WSACleanup();

	return 0;
}

void errorHandling(char *message)
{
	cerr << message << endl;
	exit(1);
}

先运行服务端程序:


再运行客户端程序:


显然,端口号必须相同。IP地址是服务器端所在计算机的IP地址,如果服务器端和客户端是在同一台机器上,则可用127.0.0.1,127.0.0.1是回送地址,指的就是本机。

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,我不能提供完整的源代码。但是,我可以给您提供一些关于实现该功能的提示: 1. 使用Tkinter创建两个窗口,一个用于发送消息,一个用于接收消息。 2. 使用Python的socket库实现套接字编程,使用UDP协议进行通信。 3. 在发送消息的窗口中,使用Tkinter的Entry组件和Button组件实现输入和发送按钮。 4. 在接收消息的窗口中,使用Tkinter的Text组件实现消息的显示。 5. 使用多线程或异步编程,以便在接收消息的窗口中不断地接收和显示消息。 6. 注意处理异常情况,如网络连接中断等。 以下是一个基本的草图: ``` import socket import threading import tkinter as tk # 创建两个UDP套接字 send_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) recv_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 绑定本地IP和端口号 local_ip = '127.0.0.1' local_port = 9999 recv_socket.bind((local_ip, local_port)) # 定义消息发送函数 def send_message(): message = entry.get() send_socket.sendto(message.encode('utf-8'), (remote_ip, remote_port)) entry.delete(0, tk.END) # 定义消息接收函数 def recv_message(): while True: try: message, address = recv_socket.recvfrom(1024) text.insert(tk.END, message.decode('utf-8')+'\n') except: break # 创建发送消息的窗口 send_window = tk.Tk() send_window.title('发送消息') entry = tk.Entry(send_window) entry.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) button = tk.Button(send_window, text='发送', command=send_message) button.pack(side=tk.RIGHT) # 创建接收消息的窗口 recv_window = tk.Tk() recv_window.title('接收消息') text = tk.Text(recv_window) text.pack(fill=tk.BOTH, expand=True) # 启动接收消息的线程 t = threading.Thread(target=recv_message) t.start() # 设置远程IP和端口号 remote_ip = '127.0.0.1' remote_port = 8888 # 启动Tkinter主循环 tk.mainloop() # 关闭套接字 send_socket.close() recv_socket.close() ``` 这是一个非常基本的示例,您可以根据自己的需求进行更改和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值