(一)
服务器端:
(1)
(2)
(3)
客户端:
(1)
(2)
服务器端:
(1)
#include <Winsock2.h>
#include <stdio.h>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
//加载套接字库
WORD wVersionRequested;//WinSock库的版本号
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1); //MAKEWORD的第一个参数为低位字节,第二个参数为高位字节
err = WSAStartup(wVersionRequested, &wsaData);
if( err != 0)
{
return 1 ;
}
//LOBYTE()取得16进制数最低位;HIBYTE()取得16进制数最高(最左边)那个字节的内容
if( LOBYTE( wsaData.wVersion) != 1 || HIBYTE( wsaData.wVersion) !=1 )
{
WSACleanup();
return -2;
}
//创建服务器端用于监听的套接字
SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
if(INVALID_SOCKET == sockSrv) { //INVALID_SOCKET就是“无效套接字”的意思
cout << "socket failed!" << endl;
WSACleanup();//释放套接字资源;
return -1;
}
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //htonl用来将主机字节顺序转换为网络字节顺序(to network long)
addrSrv.sin_family = AF_INET; //sin_family表示协议簇,一般用AF_INET表示TCP/IP协议。
addrSrv.sin_port = htons(6000); //htons是端口的转换API函数,用来将主机字节顺序转换为网络字节顺序
//绑定套接字
err = bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
if(SOCKET_ERROR == retVal) {
cout << "bind failed!" << endl;
closesocket(sServer); //关闭套接字
WSACleanup(); //释放套接字资源;
return -1;
}
//将套接字设为监听模式,准备接受客户请求
err = listen(sockSrv, 5);//5为等待连续队列的最大值
if(SOCKET_ERROR == err) {
cout << "listen failed!" << endl;
closesocket(sServer); //关闭套接字
WSACleanup(); //释放套接字资源;
return -1;
}
//接受客户端请求
SOCKADDR_IN addrClient;
int len = sizeof(SOCKADDR);
while(1)
{
//等待客户请求到来
SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrClient, &len);//sockConn建立连接的套接字
//接受数据
char recvBuf[100];
FILE *fp;
fp = fopen("..//server.txt", "w");
recv( sockConn, recvBuf, 100, 0 );
//打印接受的数据
fprintf(fp,"%s\n", recvBuf);
fclose(fp);
printf( "%s\n", recvBuf);
char sendBuf[100];
sprintf( sendBuf, "Welcome %s to the Chrisitina's World", inet_ntoa(addrClient.sin_addr));
//发送数据
send( sockConn, sendBuf, strlen(sendBuf)+1, 0 );
//关闭套接字
closesocket(sockConn);
}
//程序需要连接ws2_32.lib文件 project--link---Object/libary modules添加ws2_32.lib
return 0;
}
(2)
// Server.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "winsock2.h"
#pragma comment(lib, "ws2_32.lib")
#include <iostream>
using namespace std;
int _tmain(int argc, char* argv[]) {
const int BUF_SIZE = 64;
WSADATA wsd; //WSADATA变量
SOCKET sServer; //服务器套接字
SOCKET sClient; //客户端套接字
SOCKADDR_IN addrServ; //服务器地址
char buf[BUF_SIZE]; //接收数据缓冲区
char sendBuf[BUF_SIZE];//返回给客户端得数据
int retVal; //返回值
//初始化套结字动态库
if(WSAStartup(MAKEWORD(2,2), &wsd) != 0) { //MAKEWORD的第一个参数为低位字节,第二个参数为高位字节
cout << "WSAStartup failed!" << endl;
return 1;
}
if( LOBYTE( wsd.wVersion ) != 1 ||HIBYTE( wsd.wVersion ) != 1 ) {
//LOBYTE()取得16进制数最低位;HIBYTE()取得16进制数最高(最左边)那个字节的内容
WSACleanup();
return -1;
}
//创建服务器套接字
sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//第一个参数为协议栈(协议族)协议族决定了socket的地址类型,在通信中必须采用对应的地址。
//如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合,AF_INET表示在Internet中通信
//第二个参数:指定socket类型
//第三个参数:就是指定协议
if(INVALID_SOCKET == sServer) { //INVALID_SOCKET就是“无效套接字”的意思
cout << "socket failed!" << endl;
WSACleanup();//释放套接字资源;
return -1;
}
//服务器套接字地址
addrServ.sin_family = AF_INET; //sin_family表示协议簇,一般用AF_INET表示TCP/IP协议。
addrServ.sin_port = htons(4999); //htons是端口的转换API函数,用来将主机字节顺序转换为网络字节顺序
addrServ.sin_addr.s_addr = htonl(INADDR_ANY); //htonl用来将主机字节顺序转换为网络字节顺序(to network long)
//INADDR_ANY就是指定地址为0.0.0.0的地址,表示不确定地址,或“任意地址”。
//绑定套接字
retVal = bind(sServer, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
//将本地地址绑定到所创建的socket上,以使在网络上标识该socket ,
//在connect()或listen()调用前使用。当用socket()创建套接口后,它便存在于一个名字空间(地址族)中,但并未赋名。
//bind()函数通过给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号)。
//第一个参数:标识一未捆绑套接口的描述字
//第二个参数:赋予套接口的地址,LPSOCKADDR为结构指针,强制类型转换
//第三个参数:第二个参数的长度
if(SOCKET_ERROR == retVal) {
cout << "bind failed!" << endl;
closesocket(sServer); //关闭套接字
WSACleanup(); //释放套接字资源;
return -1;
}
//开始监听
retVal = listen(sServer, 1);
//socket监听,准备接受连接请求
//第一个参数:标识一个已捆绑未连接套接口的描述字
//第二个参数:等待连接队列的最大长度
if(SOCKET_ERROR == retVal) {
cout << "listen failed!" << endl;
closesocket(sServer); //关闭套接字
WSACleanup(); //释放套接字资源;
return -1;
}
//接受客户端请求
SOCKADDR_IN addrClient;
int addrClientlen = sizeof(addrClient);
sClient = accept(sServer,(sockaddr FAR*)&addrClient, &addrClientlen);
//为一个连接请求提供服务。addrClient包含了发出连接请求的客户机IP地址信息;返回的新socket描述服务器与该客户机的连接
//第一个参数:套接口描述字,该套接口在listen()后监听连接
//第二个参数:(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。
//这个参数的实际格式由套接口创建时所产生的地址族确定。
//第三个参数:(可选)指针,输入参数,配合第二个参数一起使用,指向存有第二个参数地址长度的整型数。
if(INVALID_SOCKET == sClient) {
cout << "accept failed!" << endl;
closesocket(sServer); //关闭套接字
WSACleanup(); //释放套接字资源;
return -1;
}
while(true){
//接收客户端数据
ZeroMemory(buf, BUF_SIZE);
//第一个参数:指向一块准备用0来填充的内存区域的开始地址。
//第二个参数:准备用0来填充的内存区域的大小,按字节来计算。
retVal = recv(sClient, buf, BUF_SIZE, 0); //从一个套接口接收数据
//第一个参数:一个标识已连接套接口的描述字
//第二个参数:用于接收数据的缓冲区。
//第三个参数:缓冲区长度
//第四个参数:指定调用方式
if (SOCKET_ERROR == retVal) {
cout << "recv failed!" << endl;
closesocket(sServer); //关闭套接字
closesocket(sClient); //关闭套接字
WSACleanup(); //释放套接字资源;
return -1;
}
if(buf[0] == '0')
break;
cout << "客户端发送的数据: " << buf <<endl;
cout << "向客户端发送数据: " ;
cin >> sendBuf;
send(sClient, sendBuf, strlen(sendBuf), 0); //向一个已连接的套接口发送数据。
//第一个参数:一个标识已连接套接口的描述字
//第二个参数:包含待发送数据的缓冲区。
//第三个参数:缓冲区中数据的长度
//第四个参数:调用执行方式
}
//退出
closesocket(sServer); //关闭套接字
closesocket(sClient); //关闭套接字
WSACleanup(); //释放套接字资源;
return 0;
}
(3)
TCP服务器端:
/*第一步:加载套接字库 WSAstartup函数,另外也可对套接字库进行版本协商,两个参数,wVersionRequested指定请求的版本号,需要注意的是高字节指定副版本,低字节指定主版本。第二个参数是一个指向wsadata的指针,WSAStartup用其加载的库版本有关的信息填在这个结构中,接收windows socket */
WORD wVersionRequested;//定义一个word类型的变量
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1
HIBYTE( wsaData.wVersion ) != 1 ) {
WSACleanup( );//终止对winsock库的使用
return;
}
/* 1.创建套接字,socket函数,返回一个套接字的描述符,三个参数,一个参数af指定地址族,第二个参数指定套接字的类型也就是TCP或UDP,第三个参数是与特定的地址家族相关的协议,如果指定为0,那么他就根据地址格式和套接字的类别, 自动为你设置一个合适的协议 如果该函数调用成功,他将返回一个新的SOCKET数据类型的套接字描述符。如果失败则返回一个 INVALID_SOCKET错误信息通过WSAGetLastID_SOCKET函数返回。 */
SOCKET socksrv=socket(AF_INET,SOCK_STREAM,0);
/*2.绑定套接字函数bind,接收三个参数,第一个指定要绑定的套接字,第二个参数指定该套接字的本地地址信息,是一个指向sockaddr
结构的指针变量,由于地址结构是为所有地址家族准备的,这个结构可能随所拥有网络协议不同而不同。所以要用第三个参数指定该地址结构的长度,显然要事先定义sockaddr结构体。
另外,因为实际要求的是内存区,所以对于不同的协议家族,用不同的结构来替换。常用的两个函数
inet_addr(),将点十进制的IP地址转换为适合分配给s_addr的u_long类型的数值
inet_ntoa()函数起相反的作用*/
SOCKADDR_IN addrsrv;
addrsrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY)
addrsrv.sin_family=AF_INET;
addrsrv.sin_port=htons(6000);
bind(socksrv,(SOCKADDR*)&addrsrv,sizeof(SOCKADDR));
//4.将套接字设置为监听模式listen函数,第一个参数指定套机字,第二个参数设置等待连接队列的长度,此处设为5
listen(socaksrv,5);
/*5.设置循环,不断地连接请求的到来,
首先定义一个地址结构体变量来接受客户的地质结构信息。然后定一个整形变量存储地址长度,为防止调用失败设置一个初始值
*/
SOCKADDR_IN addrClient;
int len=sizeof(SOCKADDR);
/*
6.在while循环中,用一个函数来等待客户的连接到来并接受客户的连接请求。accept函数,成功后会返回一个新的连接套接字的描述符,而原来的套接字则继续监听客户的连接请求
*/
while(1)
{
SOCKET sockConn=accept(socksrv,(SOCKADDR*)&addrClient,&len);
/*7.进行通信,向客户端发送数据,send函数
*/
char sendBuf[100];
sprintf(sendBuf,"welcome %s to MFC",inet_ntoa(addrClient.sin_addr));//ip地址
send(sockConn,sendBuf,strlen(sendBuf)+1,0);
/*8.同时可以从客户端接受数据用recv函数*/
char recvBuf[100];
recv(sockConn,recvBuf,100,0);
printf("%s\n",recvBuf);//打印接收到的数据
//9.关闭套接字
closesocket(sockConn);
}
客户端:
(1)
#include <Winsock2.h>
#include <stdio.h>
/******************************************************************************
**File: SOCKSrv.cpp
**Created: July 30th 2009
**Author: FreeKing
**Description: 关于socket编程基于TCP/IP协议的客户端端
*******************************************************************************/
int main(int argc, char* argv[])
{
//加载套接字库
WORD wVersionRequested;//WinSock库的版本号
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1);
err = WSAStartup(wVersionRequested, &wsaData);
if( err != 0)
{
return -1 ;
}
if( LOBYTE( wsaData.wVersion) != 1 || HIBYTE( wsaData.wVersion) !=1 )
{
WSACleanup();
return -2;
}
//创建套接字
SOCKET sockClient = socket( AF_INET,SOCK_STREAM, 0 );
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
//向服务器发出连接请求
connect( sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
//发送数据
send(sockClient, "This is Dong Liu", strlen( "This is Dong Liu" )+1, 0 );
//接受数据
FILE *fp;
fp = fopen("..//client.txt", "a");
char recvBuf[100];
recv( sockClient, recvBuf, 100, 0 );
fprintf(fp,"%s\n", recvBuf);
fclose(fp);
printf( "%s\n", recvBuf );
//关闭套接字
closesocket(sockClient);
WSACleanup();
return 0;
}
(2)
TCP客户端:
void main()
{
WORD wVersionRequested;//定义一个word类型的变量
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE( wsaData.wVersion ) != 1 ) {
WSACleanup( );
return;
}
//第一步创建套接字
SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
//第二步,因为客户端不需要绑定,可直接去连接服务器端, //connect函数
SOCKADDR_IN addrsrv;
addrsrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1")
//127.0.0.1因为只在本机测试,故此处用本机的IP地址
addrsrv.addr_family=AF_INET;
addrsrv.addr_port=htons(6000);
connect(sockClient,(SOCKADDR*)&addrsrv,sizeof(SOCKADDR));
//第三步接收数据
char recvBuf[100];
recv(sockClient,recvBuf,100,0);
printf("%s\n",recvBuf);//将接受到的数据打印出来
send(sockClient,"this is client",strlen("this is client")+1,0);
//第四步 关闭套接字
closesocket(sockClient);
WSAClenup();
}