实现socket通信.docx
- 文档编号:5260202
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:23
- 大小:27.85KB
实现socket通信.docx
《实现socket通信.docx》由会员分享,可在线阅读,更多相关《实现socket通信.docx(23页珍藏版)》请在冰豆网上搜索。
实现socket通信
基于visualc++之windows核心编程代码分析(10)实现socket通信
分类:
VC++编程技术VisualC++2010编程技术VisualStudio2012Windows82011-12-1711:
32120人阅读评论(0)收藏举报
在多台计算机之间实现通信,最常见的方法有两种:
Socket通信与UDP通信。
Socket是一种基于TCP/IP协议,建立稳定连接的点对点通信,它的特点是安全性高,数据
不会丢失,但是很占系统资源。
在JAVA中,ServerSocket类和Socket类为我们实现了Socket通信,建立通信的一般步骤是:
1。
建立服务器
ServerSocketss=newServerSocket(端口号);
Socketsocket=ss.accept();
这样,我们就已经建立了服务器,其中accept()方法会阻塞,知道有客户发送一个连接请求,我们可以通过socket.getInputStream()和socket.getOutputStream()来获得输入输出流,如调用socket.getInputStream()获得一个输入流,实际上这个流就是连接对方的一个输出流,流的操作与文件流操作相同,我们可以用操作文件的方法来操作它们。
2。
建立客户端
Socketsocket=newSocket(主机名,端口号)
客户端只需这一句代码就可以与服务器取得连接,这里的主机名应为服务器的IP地址,端口号是服务器用来监听该程序的端口,同样可以通过socket.getInputStream()和socket.getOutputStream()来获得输入输出流。
在以上程序中,已经实现了一个最简单的客户端和服务器的通信。
但是,还有一些问题。
首先,这个通信只执行一次,程序就将结束。
因为我们只读了一次输入流,如果想要建立客户与服务器之间的稳定的会话,就要用到多线程:
Threadthread=newThread(newSender());
thread.start();
InputStreaminput=socket.getInputStream();
BufferedReaderbr=newBufferedReader(newInputStreamReader(input));
while(true){
br.readLine();
}
其中,Sender是一个实现了Runnable接口的类,用它来专门负责发送数据,主线程只需要不听地接受数据就行。
Sender类中的run()方法应该具有以下代码:
PrintWriterpw=newPrintWriter(socket.getOutputStream());
while(true){
pw.println(数据);
}
即使按上面的方式做了,程序还是有问题,因为它只能在一个时间内为一个客户服务,不能同时为多个客户服务,如多要想同时为多个客户服务,服务器应具有类似以下的代码:
ServerSockerss=newServerSocker(端口号);
socket=null;
while(true){
socket=ss.accept();
Threadthread1=newThread(newSender());
thread1.start();
Threadthread2=newThread(newReceiver());
thread2.start();
}
在这里,新开启了2个线程分别负责接收和发送。
Receiver是一个与Sender非常相似的类,它主要用来接收数据。
在客户端,我们同样应开启2个线程:
Socketsocket=newSocket(服务器IP,端口号);
Sendersender=newSender(socket);
Threadthread1=newThread(sender);
thread1.start();
Receiverreceiver=newReceiver(socket);
Threadthread2=newThread(receiver);
thread2.start();
我们来亲自动手实现案例
实现客户端
viewplaincopytoclipboardprint?
1./* 头文件 */
2.#include
3.#include "winsock2.h"
4./* 常量 */
5.#define RECV_BUFFER_SIZE 8192
6.
7./*************************************
8.* main
9.* 功能 socket通信客户端
10.**************************************/
11.void main(int argc, char* argv[])
12.{
13. // 变量定义
14. SOCKADDR_IN clientService;// 地址
15. SOCKET ConnectSocket;// socket
16. WSADATA wsaData;// 库
17. LPVOID recvbuf;// 接收缓存
18. int bytesSent;
19. int bytesRecv = 0;
20. char sendbuf[32] = "get information";// 默认发送的数据
21.
22. // 初始化socket库, 保存ws2_32.dll已经加载
23. int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
24. if (iResult !
= NO_ERROR)
25. printf("Error at WSAStartup()\n");
26.
27. // 创建socket
28. ConnectSocket = socket(AF_INET, // IPv4
29. SOCK_STREAM, // 顺序的、可靠的、基于连接的、双向的数据流通信
30. IPPROTO_TCP// 使用TCP协议
31. );
32. if (ConnectSocket == INVALID_SOCKET)
33. {
34. printf("Error at socket():
%ld\n", WSAGetLastError());
35. WSACleanup();
36. return;
37. }
38.
39. // 设置服务端的通信协议、IP地址、端口
40. clientService.sin_family = AF_INET;
41. clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
42. clientService.sin_port = htons( 10000 );
43.
44. // 连接到服务端
45. if ( connect(
46. ConnectSocket, // socket
47. (SOCKADDR*) &clientService, // 地址
48. sizeof(clientService) // 地址的大小
49. ) == SOCKET_ERROR)
50. {
51. printf( "Failed to connect(%d)\n",WSAGetLastError() );
52. WSACleanup();
53. return;
54. }
55. // 准备发送数据
56. // 如果输入参数是-d,那么发送的数据是“download file”否则是"get information"
57. if(argc ==2 && (!
lstrcmp(argv[1], "-d")))
58. {
59. lstrcpyn(sendbuf, "download file", 32);
60. }
61. // 向服务端发送数据
62. bytesSent = send( ConnectSocket, // socket
63. sendbuf,// 发送的数据
64. lstrlen(sendbuf)+1,// 数据长度
65. 0 );// 无标志
66.
67. if(bytesSent == SOCKET_ERROR)
68. {
69. printf( "send error (%d)\n", WSAGetLastError());
70. closesocket(ConnectSocket);
71. return;
72. }
73. printf( "Bytes Sent:
%ld\n", bytesSent );
74.
75. // 准备接收数据
76. recvbuf = HeapAlloc(GetProcessHeap(), 0, RECV_BUFFER_SIZE);
77. // 循环接收
78. while( bytesRecv !
= SOCKET_ERROR )
79. {
80. //Sleep(50);
81. bytesRecv = recv( ConnectSocket, // socket
82. recvbuf, // 接收数据缓存
83. RECV_BUFFER_SIZE,// 缓存大小
84. 0 );// 无标志
85. if ( bytesRecv == 0 )
86. {
87. printf( "Connection Closed.\n");
88. break;
89. }
90. // TODO,处理接收的数据,这里只简单的将收到的数据大小显示
91. printf( "Bytes Recv:
%ld\n", bytesRecv );
92. }
93. HeapFree(GetProcessHeap(), 0, recvbuf);
94. WSACleanup();
95. return;
96.}
实现服务端
viewplaincopytoclipboardprint?
1./* 头文件 */
2.#include
3.#include
4.#include
5./* 常量 */
6.#define DEFAULT_PORT "10000" // 端口
7.#define MAX_REQUEST 1024 // 接收数据的缓存大小
8.#define BUF_SIZE 4096 // 发送数据的缓存大小
9.
10./*************************************
11.* CommunicationThread
12.* 功能 用于接收和发送数据的线程
13.* 为每一个连接的客户端创建一个接收发送数据的线程,
14.* 可以使用多个客户端同时连接到服务端
15.* 参数 lpParameter,SOKCET
16.**************************************/
17.DWORD WINAPI CommunicationThread(
18. LPVOID lpParameter
19. )
20.{
21. DWORD dwTid = GetCurrentThreadId();
22. // 获得参数sokcet
23. SOCKET socket = (SOCKET)lpParameter;
24. // 为接收数据分配空间
25. LPSTR szRequest = HeapAlloc(GetProcessHeap(),0, MAX_REQUEST);
26. int iResult;
27. int bytesSent;// 用于保存send的返回值,实际发送的数据的大小
28.
29. // 接收数据
30. iResult = recv(socket, // socket
31. szRequest, // 接收缓存
32. MAX_REQUEST, // 缓存大小
33. 0);// 标志
34. if (iResult == 0)// 接收数据失败,连接已经关闭
35. {
36. printf("Connection closing...\n");
37. HeapFree(GetProcessHeap(), 0 ,szRequest);
38. closesocket(socket);
39. return 1;
40. }
41. else if (iResult == SOCKET_ERROR)// 接收数据失败,socket错误
42. {
43. printf("recv failed:
%d\n", WSAGetLastError());
44. HeapFree(GetProcessHeap(), 0 ,szRequest);
45. closesocket(socket);
46. return 1;
47. }
48. else if (iResult > 0) // 接收数据成功
49. {
50. // 显示接收到的数据
51. printf("\tCommunicationThread(%d)\tBytes received:
%d\n", dwTid, iResult);
52. printf("\tCommunicationThread(%d)\trequest string is (%s)\n",dwTid, szRequest);
53.
54. // 如果接收到的数据是"download file"
55. if (lstrcmpi(szRequest, "download file") == 0)
56. {
57. // 读取文件download.txt将发送
58. HANDLE hFile;
59. LPVOID lpReadBuf; // 发送缓存
60. DWORD dwBytesRead;
61. DWORD dwFileSize;
62. DWORD dwSendFile = 0;
63. hFile = CreateFile("download.txt",
64. GENERIC_READ,
65. FILE_SHARE_READ,
66. NULL,
67. OPEN_EXISTING,
68. FILE_ATTRIBUTE_NORMAL,
69. NULL);
70.
71. if (hFile == INVALID_HANDLE_VALUE)
72. {
73. printf("\tCommunicationThread\tCould not open file (error %d)\n",
74. GetLastError());
75. send(socket, "error", 6, 0);
76. closesocket(socket);
77. return 1;
78. }
79. // 分配发送数据缓存
80. lpReadBuf = HeapAlloc(GetProcessHeap(), 0 , BUF_SIZE);
81. // 获取文件大小
82. dwFileSize = GetFileSize(hFile, NULL);
83. // 循环发送
84. while
(1)
85. {
86. // 读文件到缓存
87. if(!
ReadFile(hFile, lpReadBuf, BUF_SIZE, &dwBytesRead, NULL))
88. {
89. printf("\tCommunicationThread\tCould not read from file (error %d)\n",
90. GetLastError());
91. closesocket(socket);
92. CloseHandle(hFile);
93. return 1;
94. }
95. // 发送读取的文件数据
96. bytesSent = send(socket, lpReadBuf, dwBytesRead, 0);
97. if( bytesSent == SOCKET_ERROR)
98. {
99. printf("\tCommunicationThread\tsend error %d\n",
100. WSAGetLastError());
101. closesocket(socket);
102. CloseHandle(hFile);
103. return 1;
104. }
105. // 显示发送数据的大小
106. printf("\tCommunicationThread(%d)\tsend %d bytes\n", dwTid, bytesSent);
107. // 累加,已经发送的大小
108. dwSendFile += dwBytesRead;
109. // 如果所有文件数据都已经发送
110. if(dwSendFile == dwFileSize)
111. {
112. printf("\tCommunicationThread\tFile download ok\n");
113. break;// 退出循环
114. }
115. }
116. // 释放内存、关闭连接,关闭文件
117. HeapFree(GetProcessHeap(), 0 , lpReadBuf);
118. CloseHandle(hFile);
119. closesocket(socket);
120. }
121.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实现 socket 通信