计算机网络作业(四)
对socket编程我还是挺熟悉的,毕竟用过python写的shadowsocks,不过那时候时候没看过这个程序的源码,最近作业是做一个最多支持5线程的迭代服务器,最好能够支持智能回复,看了一下智能回复应该能用图灵机器人的API搞定,画出来的程序流程都大概如下所示:

第一章:
服务器端
界面

启动服务器按钮对应代码
void Csocket_serverDlg::OnBnClickedOk(){ // TODO: 在此添加控件通知处理程序代码 CDialogEx::OnOK(); char *chs = m_edit_port.GetBuffer(0); UpdateData(false); char *a[] = { "main.exe",chs }; if (m_edit_port) { AfxMessageBox("服务器已经开始运行"); main(2,a); } else AfxMessageBox("请输入端口号");}###头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include <process.h>
#include <winsock2.h>
#include <windows.h>
#include<ws2tcpip.h>
#include
主要代码
xvoid error_handling(char *message){ AfxMessageBox(message); exit(1);}void WorkThread(LPVOID lpParam){ SOCKET sockListen = (SOCKET)lpParam; SOCKET sockSvr; fd_set readSet; int ret; timeval tv; char buf[5000]; while (1) { sockSvr = accept(sockListen, NULL, NULL); if (sockSvr == INVALID_SOCKET) { AfxMessageBox("accept: %d ", WSAGetLastError()); continue; } while (1) { FD_ZERO(&readSet); FD_SET(sockSvr, &readSet); tv.tv_sec = 5; tv.tv_usec = 0; ret = select(0, &readSet, NULL, NULL, &tv); if (ret == SOCKET_ERROR || ret == 0) { AfxMessageBox("Socket %d:Sekect error {%d} or Timeout!\n", sockSvr, WSAGetLastError()); break; } if (FD_ISSET(sockSvr, &readSet)) { memset(buf, 0, 500); ret = recv(sockSvr, buf, 5000, 0); /*if (ret == SOCKET_ERROR || ret == 0) { AfxMessageBox("recv error {%d} or Peer closed!\n", WSAGetLastError()); break; }*/ ret = send(sockSvr, buf, strlen(buf), 0); if (ret == SOCKET_ERROR) break; } } closesocket(sockSvr); }}int main(int argc, char *argv[]){ WSADATA Ws; int serv_sock;//服务器端socket if (WSAStartup(MAKEWORD(2, 2), &Ws) != 0) { error_handling("WSAStartup() error!"); } sockaddr_in serv_addr; // socklen_t clnt_addr_size; if (argc != 2) { printf("Usage : %s <port>\n", argv[0]); exit(1); } serv_sock = socket(AF_INET, SOCK_STREAM, 0); BOOL bReuseAddr = true; setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&bReuseAddr, sizeof(bReuseAddr)); if (serv_sock == -1) { error_handling("socket() error"); } memset(&serv_addr, 0, sizeof(serv_addr));//serv_addr全部置零,清楚变量值 serv_addr.sin_family = AF_INET;//表示使用ip地址 serv_addr.sin_addr.s_addr = INADDR_ANY;//INADDR_ANY表示我不在意Local IP,由系統自行決定 //若要指定IP,則使用inet_addr,例如:name.sin_addr.s_addr = inet_addr(“140.115.65.1”); //將IP字串轉為網路位元排列,如需要反轉換,有inet_ntoa函式可用 serv_addr.sin_port = htons(atoi(argv[1]));//绑定端口 if (bind(serv_sock, (sockaddr*)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR)//绑定 { error_handling("bind() error"); WSACleanup(); closesocket(serv_sock); return -1; } if (listen(serv_sock, 5) == SOCKET_ERROR)//对serv_sock进行监听,5表示允许5个用户请求 { error_handling("listen() error"); WSACleanup(); closesocket(serv_sock); return -1; } for (int i = 0; i < CO_THREAD_NUM; i++) _beginthread(WorkThread, 0, (LPVOID)serv_sock); // clnt_addr_size = sizeof(clnt_addr); //int nSize = sizeof(SOCKADDR); /*char buffer[BUF_SIZE] = { 0 }; //缓冲区 for (int i = 0; i < 5; i++) {*/ //clnt_sock = accept(serv_sock, (sockaddr*)&clnt_addr, &clnt_addr_size);//serv_sock接受 //int strLen = recv(clnt_sock, buffer, BUF_SIZE, 0); //接收客户端发来的数据 //send(clnt_sock, message, sizeof(message), 0); //将数据原样返回 //closesocket(clnt_sock); //关闭套接字 //memset(buffer, 0, BUF_SIZE); //重置缓冲区 //} /*if (clnt_sock == INVALID_SOCKET) { error_handling("accept() error"); } send(clnt_sock, message, sizeof(message), 0); closesocket(clnt_sock);*/ Sleep(INFINITE); closesocket(serv_sock); WSACleanup(); return 0;}客户端
控制台客户端(已实现)
xxxxxxxxxx// socket_test_cilent.cpp: 定义控制台应用程序的入口点。//using namespace std;void ErrorHandling(char* message);int main(int argc, char *argv[]){ SOCKET sock; char bufSend[BUF_SIZE]; char bufRecv[BUF_SIZE]; sockaddr_in sockAddr; char message[30]; if (argc != 3) { printf("Usage : %s <IP> <port>\n ", argv[0]); exit(1); } //初始化DLL WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) ErrorHandling("WSAStartup() error!"); //向服务器发起请求 sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { WSACleanup(); ErrorHandling("socket() error"); } memset(&sockAddr, 0, sizeof(sockAddr)); //每个字节都用0填充 sockAddr.sin_family = PF_INET; // sockAddr.sin_addr.s_addr = inet_addr(argv[1]); InetPton(AF_INET, argv[1], &sockAddr.sin_addr); sockAddr.sin_port = htons(atoi(argv[2])); if (connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) { if (sock != INVALID_SOCKET) closesocket(sock); WSACleanup(); ErrorHandling("connect() error"); } else { printf("成功连接"); } //获取用户输入的字符串并发送给服务器 printf("请输入要向服务器发送的信息:\n"); fd_set readSet; struct timeval tv; int ret, len; while (1) { memset(bufSend, 0, 1000); gets_s(bufSend); if (!strcmp(bufSend, "quit\n") || !strcmp(bufSend, "QUIT\n") || !strcmp(bufSend, "Quit\n")) { WSACleanup(); //终止使用 DLL printf("你已经退出"); exit(0); } len = strlen(bufSend); if (len > 997) len = 997; bufSend[len] = '\r'; bufSend[len + 1] = '\n'; bufSend[len + 2] = 0; ret = send(sock, bufSend, strlen(bufSend), 0); if (ret == SOCKET_ERROR) { printf("send:%d\n", WSAGetLastError()); break; } FD_ZERO(&readSet); FD_SET(sock, &readSet); tv.tv_sec = 3; tv.tv_usec = 0; ret = select(0, &readSet, NULL, NULL, NULL); if (ret == SOCKET_ERROR) { printf("select: %d", WSAGetLastError()); break; } if (ret == 0) { printf("TimeOut,No Response From Server\n"); break; } if (FD_ISSET(sock, &readSet)) { memset(bufRecv, 0, 1000); ret = recv(sock, bufRecv, 1000, 0); if (ret == SOCKET_ERROR) { printf("recv: %d\n", WSAGetLastError()); break; } else { printf("%s\n", bufRecv); } } if (sock != INVALID_SOCKET) { closesocket(sock); } } WSACleanup(); printf("Stopped.\n"); return 0;}void ErrorHandling(char* message){ fputs(message,stderr); fputc('\n', stderr); exit(1);}测试gif

调用图灵机器人(暂未实现)
能力有限,不知道怎么整合MFC程序和这个winhttp的程序整合
xxxxxxxxxxstatic wchar_t String[1024];//编码转换char *UnicodeToANSI(const wchar_t *str){ static char result[1024]; int len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, str, -1, result, len, NULL, NULL); result[len] = '\0'; return result;}wchar_t *UTF8ToUnicode(const char *str){ static wchar_t result[1024]; int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); MultiByteToWideChar(CP_UTF8, 0, str, -1, result, len); result[len] = L'\0'; return result;}wchar_t *ANSIToUnicode(const char* str){ int textlen; static wchar_t result[1024]; textlen = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); memset(result, 0, sizeof(char) * (textlen + 1)); MultiByteToWideChar(CP_ACP, 0, str, -1, (LPWSTR)result, textlen); return result;}bool GetHttpPage(void){ DWORD dwSize = 0; DWORD dwDownloaded = 0; LPSTR pszOutBuffer = NULL; static HINTERNET hSession = WinHttpOpen(L"A Tuling API Example Program/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); static HINTERNET hConnect = NULL, hRequest = NULL; BOOL bResults = FALSE; //从控制台读出一行文字,注意读出来的内容是ANSI编码的,我们需要转换成 Unicode编码 static char uin[1024]; gets_s(uin); wsprintf(String, TULING_URL, ANSIToUnicode(uin)); //建立一个http的连接会话,给出主机名就行,可以域名,也可以是IP地址,不需要http;前缀 if (hSession) { if (!hConnect) hConnect = WinHttpConnect(hSession, L"www.tuling123.com", INTERNET_DEFAULT_HTTP_PORT, 0); } //创建一个HTTP请求句柄 if (hConnect) hRequest = WinHttpOpenRequest(hConnect, L"GET", String, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_ESCAPE_PERCENT | WINHTTP_FLAG_REFRESH); //发送请求数据 if (hRequest) bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); // 请求结束,接收数据 if (bResults) bResults = WinHttpReceiveResponse(hRequest, NULL); else printf("Error %d has occurred.\n", GetLastError()); //如果返回值为false,可以使用getlasterror来得到错误信息,下同 //返回值的详细信息可以看微软网页,或者看这里翻译好的中文接口说明 //http://blog.csdn.net/fengsh998/article/details/8201591 // 内部使用的一个循环来确保能接受到所有数据 if (bResults) { do { //检查是否还有数据需要接收 dwSize = 0; if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) { printf("Error %u in WinHttpQueryDataAvailable.\n", GetLastError()); break; } if (!dwSize) break; //为缓冲分配内存并读取 pszOutBuffer = new char[dwSize + 1]; if (!pszOutBuffer) { printf("Out of memory\n"); break; } ZeroMemory(pszOutBuffer, dwSize + 1); if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) { printf("Error %u in WinHttpReadData.\n", GetLastError()); } else { //图灵api返回来的内容使用的是UTF-8编码,我们需要把它转换回ANSI才能在控制台显示 //printf("return:%s\n", UnicodeToANSI(UTF8ToUnicode(pszOutBuffer)) ); //因为没有使用JSON库,所以我暴力拆了这字符串。 pszOutBuffer[strlen(pszOutBuffer)-2] = '\0'; printf("小灵:%s\n\n", UnicodeToANSI(UTF8ToUnicode(pszOutBuffer)) + 23); return true; } delete[] pszOutBuffer; if (!dwDownloaded) break; } while (dwSize > 0); } //收尾,关闭被打开的句柄 if (hRequest) WinHttpCloseHandle(hRequest); if (hConnect) WinHttpCloseHandle(hConnect); if (hSession) WinHttpCloseHandle(hSession); return false;}int main(void){ system("color F0"); system("title 会聊天的图灵机器人 ●﹏●"); printf("\n 我是小灵,快来和我聊天吧! ●▽●\n\n"); do{ printf("我:"); } while (GetHttpPage()); system("pause"); return 0;}客户端带界面版本(有问题,未调试)
发送按钮对应的实现代码
xxxxxxxxxxvoid Csocket_clientDlg::OnBnClickedButton2(){ // TODO: 在此添加控件通知处理程序代码 UpdateData(true); char *ip = m_edit_servaddr.GetBuffer(0); char *port = m_edit_servport.GetBuffer(0); char *argv[] = { "main.exe",ip,port }; CString str; m_chatedit.GetWindowTextA(str); string str1 = str.GetBuffer(0); strcpy_s(bufSend, str1.c_str()); UpdateData(false); main(3, argv);}主要代码
xxxxxxxxxxvoid ErrorHandling(char* message);int main(int argc, char *argv[]){ Csocket_clientDlg mfc; SOCKET sock; sockaddr_in sockAddr; if (argc != 3) { //printf("Usage : %s <IP> <port>\n ", argv[0]); AfxMessageBox("Usage : main.exe <IP> <port>\n "); exit(1); } //初始化DLL WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) ErrorHandling("WSAStartup() error!"); //向服务器发起请求 sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { WSACleanup(); ErrorHandling("socket() error"); } memset(&sockAddr, 0, sizeof(sockAddr)); //每个字节都用0填充 sockAddr.sin_family = PF_INET; // sockAddr.sin_addr.s_addr = inet_addr(argv[1]); InetPton(AF_INET, argv[1], &sockAddr.sin_addr); sockAddr.sin_port = htons(atoi(argv[2])); if (connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) { if (sock != INVALID_SOCKET) closesocket(sock); WSACleanup(); ErrorHandling("connect() error"); } else { //printf("成功连接"); AfxMessageBox("成功连接"); } fd_set readSet; struct timeval tv; int ret, len; while (1) { if (!strcmp(bufSend, "quit\n") || !strcmp(bufSend, "QUIT\n") || !strcmp(bufSend, "Quit\n")) { WSACleanup(); //终止使用 DLL AfxMessageBox("你已经退出"); exit(0); } len = strlen(bufSend); if (len > 997) len = 997; bufSend[len] = '\r'; bufSend[len + 1] = '\n'; bufSend[len + 2] = 0; ret = send(sock, bufSend, strlen(bufSend), 0); if (ret == SOCKET_ERROR) { AfxMessageBox("send:%d\n", WSAGetLastError()); break; } FD_ZERO(&readSet); FD_SET(sock, &readSet); tv.tv_sec = 3; tv.tv_usec = 0; ret = select(0, &readSet, NULL, NULL, NULL); if (ret == SOCKET_ERROR) { AfxMessageBox("select: %d", WSAGetLastError()); break; } if (ret == 0) { AfxMessageBox("TimeOut,No Response From Server\n"); break; } if (FD_ISSET(sock, &readSet)) { memset(bufRecv, 0, 1000); ret = recv(sock, bufRecv, 1000, 0); if (ret == SOCKET_ERROR) { AfxMessageBox("recv: %d\n", WSAGetLastError()); break; } else { mfc.m_chatlog.SetSel(-1, -1); mfc.m_chatlog.ReplaceSel((LPCTSTR)bufRecv); } } if (sock != INVALID_SOCKET) { closesocket(sock); } } WSACleanup(); AfxMessageBox("Stopped.\n"); return 0;}void ErrorHandling(char* message){ AfxMessageBox(message); exit(1);}头文件
stdafx.h
xxxxxxxxxxvoid ErrorHandling(char* message);extern SOCKET sock;using namespace std;extern char bufSend[BUF_SIZE];extern char bufRecv[BUF_SIZE];extern sockaddr_in sockAddr;extern int count;stdafx.cpp
xxxxxxxxxxSOCKET sock;char bufSend[BUF_SIZE] = { 0 };char bufRecv[BUF_SIZE] = { 0 };sockaddr_in sockAddr;int count=0;第二章
客户端界面
连接按钮对应代码
char *ip = m_addr.GetBuffer(0);
char *port = m_port.GetBuffer(0);
UpdateData(false);
char *argv[] = { "main.exe",ip,port };
main(3, argv);
主程序代码
void ErrorHandling(char* message);
int main(int argc, char *argv[])
{
CTCPsocketDlg mfc;
SOCKET sock;
sockaddr_in sockAddr;
if (argc != 3)
{
//printf("Usage : %s <IP> <port>\n ", argv[0]);
AfxMessageBox("Usage : main.exe <IP> <port>\n ");
exit(1);
}
//初始化DLL
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
ErrorHandling("WSAStartup() error!");
//向服务器发起请求
char message[30];
int strlen = 0;
int idx = 0, readlen = 0;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
WSACleanup();
ErrorHandling("socket() error");
}
memset(&sockAddr, 0, sizeof(sockAddr)); //每个字节都用0填充
sockAddr.sin_family = PF_INET;
// sockAddr.sin_addr.s_addr = inet_addr(argv[1]);
InetPton(AF_INET, argv[1], &sockAddr.sin_addr);
sockAddr.sin_port = htons(atoi(argv[2]));
if (connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
/*if (sock != INVALID_SOCKET)
closesocket(sock);
WSACleanup();*/
ErrorHandling("connect() error");
}
/*else
{
//printf("成功连接");
AfxMessageBox("成功连接");
}*/
while (readlen = recv(sock, &message[idx++], 1, 0))
{
if (readlen == -1)
ErrorHandling("read() error!");
strlen+= readlen;
}
mfc.m_mess = message;
mfc.m_read_count = strlen;
closesocket(sock);
WSACleanup();
return 0;
}
void ErrorHandling(char* message)
{
AfxMessageBox(message);
exit(1);
}
35页第6题
将客户端内的
while (readlen = recv(sock, &message[idx++], 1, 0))
{
if (readlen == -1)
ErrorHandling("read() error!");
strlen+= readlen;
}
改为
for(int i=0;i<3000:i++)
printf("write Busy");
while (readlen = recv(sock, &message[idx++], strlen(message), 0))
{
if (readlen == -1)
ErrorHandling("read() error!");
strlen+= readlen;
}
将服务器端内的
send(sock,message,strlen(message),0);
改为
if(strlen(message)>0)
for(int i=0;i<strlen(message);i++)
write(sock,message,1,0)
else
printf("write() error!");
总结
我再也不想用mfc工程写GUI界面了。
If the payout channel had filled up, the payout became extra beneficiant; if nearly empty, the payout turned less so . With microprocessors now ubiquitous, the computer systems inside fashionable slot machines permit producers 우리카지노 to assign a different probability to every image on every reel. To the player, it'd appear that a successful image was "so shut", whereas in reality the probability is way lower.
回复删除