第一章:
服务器端
界面
启动服务器按钮对应代码
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
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#define BUF_SIZE 5000
#define CO_THREAD_NUM 5
主要代码
void 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;
}
客户端
控制台客户端(已实现)
// socket_test_cilent.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#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 <iostream>
#pragma comment(lib, "ws2_32.lib")
#include <Ws2tcpip.h>
using namespace std;
#define BUF_SIZE 5000
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 的程序整合
#include <iostream>
#include <Windows.h>
#include <winhttp.h>
#pragma comment(lib,"winhttp.lib")
#define TULING_URL L"www.tuling123.com/openapi/api?key=这里换成你自己从图灵申请的API啦&info=%s"
static 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;
}
客户端带界面版本(有问题,未调试)
发送按钮对应的实现代码
void 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);
}
主要代码
void 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
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32.lib")
#include <Ws2tcpip.h>
void ErrorHandling(char* message);
extern SOCKET sock;
#define BUF_SIZE 5000
#include <iostream>
using namespace std;
extern char bufSend[BUF_SIZE];
extern char bufRecv[BUF_SIZE];
extern sockaddr_in sockAddr;
extern int count;
stdafx.cpp
SOCKET 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!");