赞
踩
不只是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!”。
最后说明一个问题:这里可以说使用了停-等协议,发送一个数据包收到确认再发送下一个数据包,否则客户端连续发送完所有数据包(包括结束标志),服务器收不到结束标志,就会一直阻塞下去。具体原因还没想明白,一开始没有加"接收确认"的时候,调试是没问题的,但是运行就会阻塞。
上面就是工作流程,结束后就可以关闭套接字了。
附上源代码:
客户端:
- #include <stdio.h>
- #include <winsock2.h>
- #include <tchar.h>
- #pragma comment(lib, "ws2_32.lib") //加载库文件
-
- char FILE_FLAG[12] = "xmzulesile"; // 发送文件的标志
- char FILE_SEND_OVER[10] = "over"; // 发送文件结束的标志
-
- int main()
- {
- // 初始化Winsock
- WSADATA wsaData;
- int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
- if (iResult != NO_ERROR)
- {
- printf_s("failed to initialize!\n");
- return 0;
- }
-
- // 建立socket
- SOCKET m_socketServer;// 连接服务器的套接字
- m_socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (m_socketServer == INVALID_SOCKET)
- {
- printf_s("failed to create client socket!\n");
- WSACleanup();
- return 0;
- }
-
- sockaddr_in clientAddr;
- clientAddr.sin_family = AF_INET;
- clientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
- clientAddr.sin_port = htons(3579);
-
- // 连接到服务器
- if (connect(m_socketServer, (SOCKADDR*)&clientAddr, sizeof(clientAddr)) == SOCKET_ERROR)
- {
- printf_s("failed to connect\n");
- closesocket(m_socketServer);
- WSACleanup();
- return 0;
- }
-
- char c;
- char buf[1024 + 1] = { 0 };
- char filename[255];
- FILE *fp = NULL;
-
- //send(m_socketServer, buf, strlen(buf), 0);
- // 发送数据
- while (TRUE)
- {
- printf_s("发送:1.消息;2.文件\n");
- if ((c = getchar()) == '1')
- {
- getchar();// 丢弃回车符
- gets_s(buf, 1024);// 读取消息
- send(m_socketServer, buf, strlen(buf), 0);
- }
- else if (c == '2')
- {
- getchar();// 丢弃回车符
- printf_s("请输入本地文件路径: ");
- scanf_s("%s",&filename, 255);
- getchar();// 丢弃回车符
- if (fopen_s(&fp, filename, "rb+"))
- {
- ::MessageBox(NULL, _T("failed to open file in client"), NULL, 0);
- return 0;
- }
- send(m_socketServer, FILE_FLAG, sizeof(FILE_FLAG), 0);//通知服务器将要发送文件
- // 读取文件
- int i = fread(buf, 1, 1024, fp);
- while (i > 0)
- {
- //这里可以说使用停-等协议,发送一个数据包收到确认再发送下一个数据包
- //否则客户端连续发送完所有数据包(包括结束标志),服务器收不到结束标志,就会一直阻塞下去
- //具体原因还没想明白,一开始没有加"接收确认"的时候,调试是没问题的,但是运行就会阻塞
- send(m_socketServer, buf, i, 0);
- recv(m_socketServer, buf, 1024, 0);//接收确认
- SecureZeroMemory(buf, sizeof(buf));
- i = fread(buf, 1, 1024, fp);
- }
- if (ferror(fp))
- {
- MessageBox(NULL, _T("fread error"), NULL, 0);
- return 0;
- }
- //告诉服务器发送完毕
- send(m_socketServer, FILE_SEND_OVER, sizeof(FILE_SEND_OVER), 0);
- //接收通知(服务器接收完毕)
- int ret = recv(m_socketServer, buf, 1024, 0);
- if (ret == 0)
- {
- printf("Recv data error: %d\n", WSAGetLastError());
- return 0;
- }
- if (buf[0])//输出服务器发过来的消息
- {
- buf[ret] = 0;
- printf_s("Server:%s\n", buf);
- }
- if (fp)
- {
- fclose(fp);//关闭文件
- fp = NULL;
- }
- }
- else
- {
- getchar();
- printf_s("incorrect input\n");
- }
- }
-
- closesocket(m_socketServer);
- WSACleanup();
- return 0;
- }
- #include <WinSock2.h>
- #include <iostream>
- #include <string.h>
- #include <tchar.h>
- #pragma comment(lib, "ws2_32.lib")
-
- char FILE_FLAG[12] = "xmzulesile"; // 客户端发来文件的标志
- char FILE_SEND_OVER[10] = "over"; // 客户端发送文件结束的标志
-
- //接收文件
- unsigned recvFile(SOCKET s, const char *filename)
- {
- FILE *fp;
- char buf[1024] = { 0 };
- int ret = 0;
- if (fopen_s(&fp, filename, "wb+"))
- {
- ::MessageBox(NULL, _T("failed to write file in server"), NULL, 0);
- return 0;
- }
- do
- {
- //接收数据
- ret = recv(s, buf, 1024, 0);
- if (ret == 0)
- {
- printf("Recv data error: %d\n", WSAGetLastError());
- return 0;
- }
- //是否接收结束
- if (!strcmp(buf, FILE_SEND_OVER))
- {
- send(s, "Received!", 10, 0);//通知发送端全部接收完毕
- break;
- }
- else
- {
- //把数据写入打开的文件
- fwrite(buf, 1, ret, fp);
- send(s, "Got it", 10, 0);//发送确认
- SecureZeroMemory(buf, sizeof(buf));
- }
- } while (ret > 0);
-
- if (fp)
- {
- fclose(fp);
- fp = NULL;
- }
- return 0;
- }
-
- int main()
- {
- WSADATA wsaData;
- int iInit = WSAStartup(MAKEWORD(2, 2), &wsaData);
- if (iInit != NO_ERROR)
- {
- printf_s("failed to initialize!\n");
- return 0;
- }
-
- SOCKET m_socketListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (m_socketListen == INVALID_SOCKET)
- {
- printf_s("failed to create server socket!\n");
- WSACleanup();
- return 0;
- }
-
- sockaddr_in serverAddr;
- serverAddr.sin_family = AF_INET;
- serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
- serverAddr.sin_port = htons(3579);
-
- //bind
- if (bind(m_socketListen, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
- {
- printf_s("failed to bind!\n");
- closesocket(m_socketListen);
- WSACleanup();
- return 0;
- }
-
- //listen
- if (listen(m_socketListen, 1) == SOCKET_ERROR) {
- printf_s("listen failed\n");
- closesocket(m_socketListen);
- WSACleanup();
- return 0;
- }
-
- //accept
- //从监听socket上接受一个等待的连接请求后,accept()函数为新创建的连接返回一个新的socket
- SOCKET m_socketClient = accept(m_socketListen, NULL, NULL);// 跟客户端连接的套接字
- if (m_socketClient == INVALID_SOCKET) {
- wprintf(L"accept failed with error: %ld\n", WSAGetLastError());
- closesocket(m_socketListen);
- WSACleanup();
- return 0;
- }
-
- int bytes = SOCKET_ERROR;
- char buf[1024] = { 0 };
-
- //接收数据
- while (TRUE)
- {
- if((bytes = recv(m_socketClient, buf, 1024, 0)) == 0)
- {
- break;
- }
- if (!strcmp(FILE_FLAG, buf))
- {
- printf_s("Here comes a file\n");
- recvFile(m_socketClient, "d:\\recv");
- }
- else
- {
- buf[bytes] = '\0';// 字符串结尾标志
- printf_s("Client:%s\n", buf);
- }
- }
-
- closesocket(m_socketListen);
- WSACleanup();
- return 0;
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。