参考《精通Windows Sockets网络开发--基于Visual C++实现》
该程序由客户端和服务器端组成,实现的功能是客户端向服务器发送“MyTcp”字符串,服务器接收到该字符串,并显示出来。
客户端发送字符串后退出,服务器显示字符串后退出。
服务器实现,也即当前的TcpExample
添加库文件ws2_32.lib为2.2版,1.1版socket为wsock32.lib,
#include <stdio.h> #include <WINSOCK2.H> #define BUF_SIZE 64 //缓冲区大小 char buf[BUF_SIZE]; //接收数据缓冲区 SOCKET sClient;
WSADATA wsd; //WSADATA变量 int retVal; //返回值 if (WSAStartup(MAKEWORD(2,2),&wsd) != 0) { printf("WSAStartup 失败!\n"); return 1; }
//创建套接字
//创建套接字 SOCKET sServer; //服务器套接字 sServer=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if (INVALID_SOCKET == sServer) { printf("创建套接字失败!\n"); WSACleanup();//释放套接字资源 return -1; }
//首先定义服务地址 SOCKADDR_IN addrServ; //服务器套接字地址 addrServ.sin_family=AF_INET; addrServ.sin_port=htons(4999); /* addrServ.sin_addr.S_addr=INADDR_ANY; addrServ.sin_addr.S_addr=INADDR_ANY; 原书错误见winsock2.h,in_addr只有一个联合体类型的S_un成员变量 * struct in_addr { union { struct{ u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; struct{ u_short s_w1,s_w2; } S_un_w; u_longS_addr; } S_un; */ addrServ.sin_addr.S_un.S_addr=INADDR_ANY; //绑定套接字 retVal=bind(sServer,(LPSOCKADDR)&addrServ,sizeof(SOCKADDR_IN)); if(SOCKET_ERROR == retVal) { printf("绑定失败!\n"); closesocket(sServer);//关闭套接字 WSACleanup();//释放套接字资源 return-1; }
//开始监听,设置等待接受连接的队列长度为1 retVal=listen(sServer,1); if(SOCKET_ERROR == retVal) { printf("监听失败!\n"); closesocket(sServer); WSACleanup(); return-1; }
//accept函数处于阻塞状态,直到接受了一个客户端请求。当该函数返回时,新建一个套接字,同时返回该客户端的地址 //如果调用失败,则返回INVALID_SOCKET sockaddr_inaddrClient; intaddrClientlen =sizeof(addrClient); sClient=accept(sServer,(sockaddrFAR*)&addrClient,&addrClientlen); if(INVALID_SOCKET == sClient) { printf("接受客户端连接失败!\n"); closesocket(sServer); WSACleanup(); return-1; }
//接收并显示数据 //调用recv() 函数接收客户端发送的数据。在调用该函数前首先调用ZeroMemory()函数将接收数据缓冲区设置为0,最后调用printf显示数据 charbuf[128]; intBUF_SIZE=128; ZeroMemory(buf,BUF_SIZE); retVal=recv(sClient,buf,BUF_SIZE,0); if(SOCKET_ERROR ==retVal) { printf("接收数据失败!\n"); closesocket(sServer); closesocket(sClient); WSACleanup(); return-1; } printf("%s\n",buf);//输出数据
closesocket(sServer); closesocket(sClient); WSACleanup();
实现客户端
客户端主要功能是连接服务器,向服务器发送“MyTcp”字符串。客户端的实现包括
初始化套接字动态库、创建套接字、连接服务器、发送数据和退出。
1、console程序TcpClient,选中Add to current workspace,A simple Application ,
2、#include <stdio.h>,添加库文件
3、定义全局变量
#include <WINSOCK2.H> #define BUF_SIZE 64 //缓冲区大小 WSADATA wsd; //WSADATA变量 SOCKET sHost; //服务器套接字 SOCKADDR_IN servAddr; //服务器地址 char buf[BUF_SIZE]; //接收数据缓冲区 int retval; //返回值
4、初始化套接字动态库
//初始化套接字动态库 if(WSAStartup(MAKEWORD(2,2),(LPWSADATA)&wsd)!=0) { printf("WSAStartup失败!\n"); return-1; }
5、创建套接字
//创建套接字 sHost=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(INVALID_SOCKET == sHost) { printf("创建套接字失败!\n"); WSACleanup(); return-1; }
6、连接服务器
设置IP地址为127.0.0.1,服务器端口为4999.调用connect() 函数连接服务器。
//设置服务器地址 servAddr.sin_family=AF_INET; servAddr.sin_port=htons((short)4999); servAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); intnServAddlen=sizeof(servAddr); //连接服务器 retval=connect(sHost,(LPSOCKADDR)&servAddr,sizeof(servAddr)); if(SOCKET_ERROR == retval) { printf("连接服务器失败! \n"); closesocket(sHost); WSACleanup(); }
7、发送数据
//首先利用ZeroMemory设置发送数据缓冲区为0 ZeroMemory(buf,BUF_SIZE); strcpy(buf,"MyTcp"); retval=send(sHost,buf,strlen(buf),0); if(SOCKET_ERROR == retval) { printf("向服务器发送数据失败! \n"); closesocket(sHost); WSACleanup(); return-1; }
8、退出
closesocket(sHost); WSACleanup();
先运行TcpExample,再运行TcpClient。