当前位置:   article > 正文

winsock入门之建立socket_winsock创建socket

winsock创建socket

不只是winsock,几乎所有网络程序可以分为5个步骤:

1.      打开socket

2.      命名socket

3.      与另一个socket建立关联

4.      与socket之间发送和接收数据

5.      关闭socket

(一)下面主要说明连接的建立过程。

打开socket:int socket(intaf, int type, int protocol);

参数说明:

af: 地址族的类型AF_UNIXAF_INET

type: 数据格式:流SOCK_STREAM/报文SOCK_DGRAM

protocol: 协议类型

命名socket:intbind(SOCKET s, struct sockaddr FAR *addr, int namelen);

参数说明:

s:socket句柄。

addr:指向socket地址结构的指针。

namelen:addr所指向的socket结构的长度。

这里用到的一个数据结构sockaddr_in是给socket命名的关键,具体如下:

struct sockaddr_in{

         short         sin_family;//地址族

         u_short    sin_port;//端口号

         struct       in_addr    sin_addr;//地址

         char          sin_zero[8];//没用

};//这里当然都是绑定本机地址127.0.0.1

第1、2步是服务器和客户端都要做的,但是一般情况下客户端为了防止端口号冲突会采用隐式命名的方式,在向服务器发起连接的时候(调用connect()函数)协议栈会分配给客户端独有的端口号。

3.1.服务器监听客户端

int PASCAL FAR listen(SOCKETs, int backlog);

3.2.客户端发起连接

int PASCAL FAR connet(SOCKETs, struct sokaddr FAR *addr, int namelen);

3.3.服务器完成连接

从监听socket上接受一个等待的连接请求后,accept()函数为新创建的连接返回一个新的socket。

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

(二)接下来就是发送数据和关闭套接字了。

这里我实现了两个功能:发送消息和发送文件。

客户端首先选择发送类型:1.消息;2.文件

两种方式实现起来没有大差别,只是在发送文件的时候首先发送一个标志FILE_FLAG " xmzulesile "提醒服务器将要发送文件,然后服务器将接收到的字节流写入文件,客户端发送文件结束后发送一个标志FILE_SEND_OVER "over",服务器收到后知道发送结束给客户端发送”Received!”。

最后说明一个问题:这里可以说使用了停-等协议,发送一个数据包收到确认再发送下一个数据包,否则客户端连续发送完所有数据包(包括结束标志),服务器收不到结束标志,就会一直阻塞下去。具体原因还没想明白,一开始没有加"接收确认"的时候,调试是没问题的,但是运行就会阻塞。

上面就是工作流程,结束后就可以关闭套接字了。

附上源代码:

客户端:

  1. #include <stdio.h>
  2. #include <winsock2.h>
  3. #include <tchar.h>
  4. #pragma comment(lib, "ws2_32.lib") //加载库文件
  5. char FILE_FLAG[12] = "xmzulesile"; // 发送文件的标志
  6. char FILE_SEND_OVER[10] = "over"; // 发送文件结束的标志
  7. int main()
  8. {
  9. // 初始化Winsock
  10. WSADATA wsaData;
  11. int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
  12. if (iResult != NO_ERROR)
  13. {
  14. printf_s("failed to initialize!\n");
  15. return 0;
  16. }
  17. // 建立socket
  18. SOCKET m_socketServer;// 连接服务器的套接字
  19. m_socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  20. if (m_socketServer == INVALID_SOCKET)
  21. {
  22. printf_s("failed to create client socket!\n");
  23. WSACleanup();
  24. return 0;
  25. }
  26. sockaddr_in clientAddr;
  27. clientAddr.sin_family = AF_INET;
  28. clientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  29. clientAddr.sin_port = htons(3579);
  30. // 连接到服务器
  31. if (connect(m_socketServer, (SOCKADDR*)&clientAddr, sizeof(clientAddr)) == SOCKET_ERROR)
  32. {
  33. printf_s("failed to connect\n");
  34. closesocket(m_socketServer);
  35. WSACleanup();
  36. return 0;
  37. }
  38. char c;
  39. char buf[1024 + 1] = { 0 };
  40. char filename[255];
  41. FILE *fp = NULL;
  42. //send(m_socketServer, buf, strlen(buf), 0);
  43. // 发送数据
  44. while (TRUE)
  45. {
  46. printf_s("发送:1.消息;2.文件\n");
  47. if ((c = getchar()) == '1')
  48. {
  49. getchar();// 丢弃回车符
  50. gets_s(buf, 1024);// 读取消息
  51. send(m_socketServer, buf, strlen(buf), 0);
  52. }
  53. else if (c == '2')
  54. {
  55. getchar();// 丢弃回车符
  56. printf_s("请输入本地文件路径: ");
  57. scanf_s("%s",&filename, 255);
  58. getchar();// 丢弃回车符
  59. if (fopen_s(&fp, filename, "rb+"))
  60. {
  61. ::MessageBox(NULL, _T("failed to open file in client"), NULL, 0);
  62. return 0;
  63. }
  64. send(m_socketServer, FILE_FLAG, sizeof(FILE_FLAG), 0);//通知服务器将要发送文件
  65. // 读取文件
  66. int i = fread(buf, 1, 1024, fp);
  67. while (i > 0)
  68. {
  69. //这里可以说使用停-等协议,发送一个数据包收到确认再发送下一个数据包
  70. //否则客户端连续发送完所有数据包(包括结束标志),服务器收不到结束标志,就会一直阻塞下去
  71. //具体原因还没想明白,一开始没有加"接收确认"的时候,调试是没问题的,但是运行就会阻塞
  72. send(m_socketServer, buf, i, 0);
  73. recv(m_socketServer, buf, 1024, 0);//接收确认
  74. SecureZeroMemory(buf, sizeof(buf));
  75. i = fread(buf, 1, 1024, fp);
  76. }
  77. if (ferror(fp))
  78. {
  79. MessageBox(NULL, _T("fread error"), NULL, 0);
  80. return 0;
  81. }
  82. //告诉服务器发送完毕
  83. send(m_socketServer, FILE_SEND_OVER, sizeof(FILE_SEND_OVER), 0);
  84. //接收通知(服务器接收完毕)
  85. int ret = recv(m_socketServer, buf, 1024, 0);
  86. if (ret == 0)
  87. {
  88. printf("Recv data error: %d\n", WSAGetLastError());
  89. return 0;
  90. }
  91. if (buf[0])//输出服务器发过来的消息
  92. {
  93. buf[ret] = 0;
  94. printf_s("Server:%s\n", buf);
  95. }
  96. if (fp)
  97. {
  98. fclose(fp);//关闭文件
  99. fp = NULL;
  100. }
  101. }
  102. else
  103. {
  104. getchar();
  105. printf_s("incorrect input\n");
  106. }
  107. }
  108. closesocket(m_socketServer);
  109. WSACleanup();
  110. return 0;
  111. }


服务器:
  1. #include <WinSock2.h>
  2. #include <iostream>
  3. #include <string.h>
  4. #include <tchar.h>
  5. #pragma comment(lib, "ws2_32.lib")
  6. char FILE_FLAG[12] = "xmzulesile"; // 客户端发来文件的标志
  7. char FILE_SEND_OVER[10] = "over"; // 客户端发送文件结束的标志
  8. //接收文件
  9. unsigned recvFile(SOCKET s, const char *filename)
  10. {
  11. FILE *fp;
  12. char buf[1024] = { 0 };
  13. int ret = 0;
  14. if (fopen_s(&fp, filename, "wb+"))
  15. {
  16. ::MessageBox(NULL, _T("failed to write file in server"), NULL, 0);
  17. return 0;
  18. }
  19. do
  20. {
  21. //接收数据
  22. ret = recv(s, buf, 1024, 0);
  23. if (ret == 0)
  24. {
  25. printf("Recv data error: %d\n", WSAGetLastError());
  26. return 0;
  27. }
  28. //是否接收结束
  29. if (!strcmp(buf, FILE_SEND_OVER))
  30. {
  31. send(s, "Received!", 10, 0);//通知发送端全部接收完毕
  32. break;
  33. }
  34. else
  35. {
  36. //把数据写入打开的文件
  37. fwrite(buf, 1, ret, fp);
  38. send(s, "Got it", 10, 0);//发送确认
  39. SecureZeroMemory(buf, sizeof(buf));
  40. }
  41. } while (ret > 0);
  42. if (fp)
  43. {
  44. fclose(fp);
  45. fp = NULL;
  46. }
  47. return 0;
  48. }
  49. int main()
  50. {
  51. WSADATA wsaData;
  52. int iInit = WSAStartup(MAKEWORD(2, 2), &wsaData);
  53. if (iInit != NO_ERROR)
  54. {
  55. printf_s("failed to initialize!\n");
  56. return 0;
  57. }
  58. SOCKET m_socketListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  59. if (m_socketListen == INVALID_SOCKET)
  60. {
  61. printf_s("failed to create server socket!\n");
  62. WSACleanup();
  63. return 0;
  64. }
  65. sockaddr_in serverAddr;
  66. serverAddr.sin_family = AF_INET;
  67. serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  68. serverAddr.sin_port = htons(3579);
  69. //bind
  70. if (bind(m_socketListen, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
  71. {
  72. printf_s("failed to bind!\n");
  73. closesocket(m_socketListen);
  74. WSACleanup();
  75. return 0;
  76. }
  77. //listen
  78. if (listen(m_socketListen, 1) == SOCKET_ERROR) {
  79. printf_s("listen failed\n");
  80. closesocket(m_socketListen);
  81. WSACleanup();
  82. return 0;
  83. }
  84. //accept
  85. //从监听socket上接受一个等待的连接请求后,accept()函数为新创建的连接返回一个新的socket
  86. SOCKET m_socketClient = accept(m_socketListen, NULL, NULL);// 跟客户端连接的套接字
  87. if (m_socketClient == INVALID_SOCKET) {
  88. wprintf(L"accept failed with error: %ld\n", WSAGetLastError());
  89. closesocket(m_socketListen);
  90. WSACleanup();
  91. return 0;
  92. }
  93. int bytes = SOCKET_ERROR;
  94. char buf[1024] = { 0 };
  95. //接收数据
  96. while (TRUE)
  97. {
  98. if((bytes = recv(m_socketClient, buf, 1024, 0)) == 0)
  99. {
  100. break;
  101. }
  102. if (!strcmp(FILE_FLAG, buf))
  103. {
  104. printf_s("Here comes a file\n");
  105. recvFile(m_socketClient, "d:\\recv");
  106. }
  107. else
  108. {
  109. buf[bytes] = '\0';// 字符串结尾标志
  110. printf_s("Client:%s\n", buf);
  111. }
  112. }
  113. closesocket(m_socketListen);
  114. WSACleanup();
  115. return 0;
  116. }


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/147147
推荐阅读
相关标签
  

闽ICP备14008679号