1.主要实现
2.c++实现
3.主要函数
1.主要简单的实现
这一节是计算机网络作业,windows socket编程,老师电脑上开一个服务器程序,公开ip地址和端口号,我们同学自己编写一个客户端,能与老师的服务器建立联系,两者能收发即可。这样的代码网上很多,而是就采用了孙鑫VC++第14讲的代码,下面是添加的一点简单注释。
其实socket完成连接功能很简单,依葫芦画瓢即可。首先来看面向连接的TCP流程图。 
面向无连接的UDP流程更加简单,如下所示:

现在用TCP协议来完成任务,下面是孙鑫老师的代码,由于我们要提前测试自己的代码,所以也用了服务器端的代码,服务器端端server代码如下:
1 #include
2 #include
3
4 void main()
5 {
6 // 以下的几句都是固定的
7 WORD wVersionRequested;
8 WSADATA wsaData;
9 int err;
10
11 wVersionRequested = MAKEWORD( 1, 1 );
12
13 err = WSAStartup( wVersionRequested, &wsaData );//该函数的功能是加载一个Winsocket库版本
14 if ( err != 0 ) {
15 return;
16 }
17
18
19 if ( LOBYTE( wsaData.wVersion ) != 1 ||
20 HIBYTE( wsaData.wVersion ) != 1 ) {
21 WSACleanup( );
22 return;
23 }
24
25
26 //真正socket编程部分
27 SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);//面向连接的可靠性服务SOCK_STRAM
28
29 SOCKADDR_IN addrSrv;//存放本地地址信息的
30 addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//htol将主机字节序long型转换为网络字节序
31 addrSrv.sin_family=AF_INET;
32 addrSrv.sin_port=htons(6001);//htos用来将端口转换成字符,1024以上的数字即可
33
34 bind(sockSrv,(SOCKADDR)&addrSrv,sizeof(SOCKADDR));//将socket绑定到相应地址和端口上
35
36 listen(sockSrv,5);//等待队列中的最大长度为5
37
38 SOCKADDR_IN addrClient;
39 int len=sizeof(SOCKADDR);
40
41 while(1)
42 {
43 SOCKET sockConn=accept(sockSrv,(SOCKADDR)&addrClient,&len);//建立一个新的套接字用于通信,不是前面的监听套接字
44 char sendBuf[100];
45 sprintf(sendBuf,”Server IP is:%s”,
46 inet_ntoa(addrClient.sin_addr));//inet_nota函数是将字符转换成ip地址
47 send(sockConn,sendBuf,strlen(sendBuf)+1,0);//服务器向客户端发送数据
48
49 char recvBuf[100];
50 recv(sockConn,recvBuf,100,0);//服务器从客户端接受数据
51 printf(“%s\\n”,recvBuf);
52 closesocket(sockConn);//关闭socket
53 }
54 }
客户端client的代码如下:
1 #include
2 #include
3
4 void main()
5 {
6 //固定格式
7 WORD wVersionRequested;
8 WSADATA wsaData;
9 int err;
10
11 wVersionRequested = MAKEWORD( 1, 1 );
12
13 err = WSAStartup( wVersionRequested, &wsaData );
14 if ( err != 0 ) {
15 return;
16 }
17
18
19 if ( LOBYTE( wsaData.wVersion ) != 1 ||
20 HIBYTE( wsaData.wVersion ) != 1 ) {
21 WSACleanup( );
22 return;
23 }
24
25 //建立通讯socket
26 SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
27
28 SOCKADDR_IN addrSrv;
29 addrSrv.sin_addr.S_un.S_addr=inet_addr(“192.168.1.24”);//设定需要连接的服务器的ip地址
30 addrSrv.sin_family=AF_INET;
31 addrSrv.sin_port=htons(6001);//设定需要连接的服务器的端口地址
32 connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//与服务器进行连接
33
34 //接受来自老师的信息
35 char recvBuf[100];
36 recv(sockClient,recvBuf,100,0);
37 printf(“来自老师的信息:\\n%s\\n”,recvBuf);
38
39 //发送信息给老师
40 send(sockClient,”姓名:小明 学号:123456789,IP地址:192.168.1.14!”,strlen(“姓名:小明 学号:123456789,IP地址:192.168.1.14!”)+1,0);
41
42 closesocket(sockClient);
43 WSACleanup();
44 }
模拟运行结果如下:
作者:tornadomeet 出处:http://www.cnblogs.com/tornadomeet
2.C++实现
//服务器
include
include // socket 所需要的头文件
pragma comment(lib,”WS2_32.lib”)// link socket 库
define PORT 9999
define BUFLEN 1024
using namespace std;
int main()
{
WSADATA wsaData;
// 1 启动并初始化winsock(WSAStarup)
if (WSAStartup(MAKEWORD(2, 2), &wsaData))//成功返回0
{
return FALSE;
}
//2 创建套接字(socket)
SOCKET sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(INVALID_SOCKET == sServer)
{
WSACleanup();
return FALSE;
}
//3 准备通信地址
SOCKADDR_IN addrServer;
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(PORT);
addrServer.sin_addr.s_addr = INADDR_ANY;//任意可用地址
//4 绑定地址与socket(bind)
if (SOCKET_ERROR==bind(sServer, (const sockaddr)&addrServer, sizeof(SOCKADDR_IN)))
{
closesocket(sServer);
WSACleanup();
return FALSE;
}
//5 监听 (listen)
if (SOCKET_ERROR == listen(sServer, SOMAXCONN))
{
closesocket(sServer);
WSACleanup();
}
// 6 等待客户端连接(accpet)
sockaddr_in addrClient;
int addrClientLen = sizeof(addrClient);
cout << “服务器启动成功,等待客户端连接中。。。。” << endl;
SOCKET sClient = accept(sServer, (sockaddr )&addrClient, &addrClientLen);
if (INVALID_SOCKET == sClient)
{
cout << WSAGetLastError() << endl;
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return FALSE;
}
//7 接收数据(recv)
char recvBuf[BUFLEN];
ZeroMemory(recvBuf, sizeof(recvBuf));
if (SOCKET_ERROR == recv(sClient, recvBuf, sizeof(recvBuf), 0))
{
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return FALSE;
}
cout << “客户端(“ << inet_ntoa(addrClient.sin_addr) << “:” << addrClient.sin_port << “):” << recvBuf << endl;
//8 发送数据
char sendBuf[BUFLEN] = “你好客户端!”;
if (SOCKET_ERROR==send(sClient, sendBuf, sizeof(sendBuf), 0))
{
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return FALSE;
}
system(“pause”);
system(“pause”);
return TRUE;
}
/
注:1:MAKEWORD把参数组成一个WORD(双字节)类型数据并返回这个WORD类型数值,高位代表(修订本)号,低位字节指定主版本号(其代表)
2:socket(AF_INET,//The Internet Protocol version 4 (IPv4) address family
SOCK_STREAM,//, two-way,This socket type uses the Transmission Control Protocol (TCP) for the Internet address family (AF_INET or AF_INET6).
IPPROTO_TCP//The Transmission Control Protocol (TCP). This is a possible value when the af parameter is AF_INET or AF_INET6 and the type parameter is SOCK_STREAM.
)
/
//客户端
include
include
pragma comment(lib,”WS2_32.lib”)
using namespace std;
define BUFLEN 1024
define PORT 9999
void getIP(charszHostaddress);
int main()
{
WSADATA wsaData;
// 1 启动并初始化winsock(WSAStarup)
if (WSAStartup(MAKEWORD(2, 2), &wsaData))//成功返回0
{
return FALSE;
}
//2 创建套接字(socket)
SOCKET sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sHost)
{
closesocket(sHost);
WSACleanup();
return FALSE;
}
//3 准备通信地址
char szHostaddress[200];
getIP(szHostaddress);
SOCKADDR_IN addrServer;
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(PORT);
addrServer.sin_addr.s_addr = inet_addr(szHostaddress);
//4 连接服务器(connect)
if (SOCKET_ERROR == connect(sHost, (const sockaddr)&addrServer, sizeof(addrServer)))
{
closesocket(sHost);
WSACleanup();
return FALSE;
}
//5 发送数据 (send)
char sendBuf[BUFLEN] = “你好服务器!”;
if (SOCKET_ERROR == send(sHost, sendBuf, sizeof(sendBuf), 0))
{
closesocket(sHost);
WSACleanup();
return FALSE;
}
cout << “客户端发送消息成功!” << endl;
//7 接收数据(recv)
char recvBuf[BUFLEN];
ZeroMemory(recvBuf, sizeof(recvBuf));
if (SOCKET_ERROR == recv(sHost, recvBuf, sizeof(recvBuf), 0))
{
closesocket(sHost);
WSACleanup();
return FALSE;
}
cout << “服务器发来的消息:” <
(pHostEnt->h_addr_list[0][1] & 0x00ff),
(pHostEnt->h_addr_list[0][2] & 0x00ff),
(pHostEnt->h_addr_list[0][3] & 0x00ff));
}
}
else
return;
}
3.winsocket中主要函数:
1.WSAstartup (连接WinSocket库) 原型如下:
Int WSAStartup (
Word WVersionregusested,
LPWSADATA LPWSAData
);
在delphi中定义如下:
function WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer; stdcall;
应用程序在使用Winsock API之前必须调用此函数,只有当此函数返回(表示应用程序与Winsock库成功建立起连接),应用程序才可以调用其它 Windows Sockets DLL 中的函数.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2. WSACleanup (断开与Winsocket库的连接)原型如下:
Int WSACleanup (Void);
在Delphi中定义如下:
function WSACleanup: Integer; stdcall;
应用程序在使用完Socket库函数之后,必须使用这个函数来释放所占用的内存.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3. Socket (套接字建立函数) 原型如下
SOCKET Socket(
Int af,
int type,
int Protocol
);
在Delphi中定义如下 :
function socket(af, Struct, protocol: Integer): TSocket; stdcall;
使用该函数可以建立使用特定协议的网络套接字,例如UDP协议的写法
var
S : TSocket;
begin
WSAStartup();
S := Socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
WSACleanup;
end;
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
4. bind(套接字绑定函数) 原型如下:
Int bind (
SOCKET S,
coust struct sockaddr FAR name,
int namelen
);
在Delphi中定义如下 :
function bind(s: TSocket; var addr: TSockAddr; namelen: Integer): Integer; stdcall;
s : 是通过Socket建立的套接字, addr是指向描述通讯对象的结构体(TSockAddr)的指针,namelen是TSockAddr结构体的长度
TSockAddr结构体有三个成员.
1. IP地址
2. 端口
3. 地址类型
---------------------------------------------------------------------------------------------------------------------------------------------- -------------- ---
5. listen(套接字监视函数) 原型如下:
int listen(
SOCKET s,
int backlog
);
Delphi中定义如下 :
function listen(s: TSocket; backlog: Integer): Integer; stdcall;
listen一般用于服务端程序.
s 是刚才用socket创建的套接字. backlog用于设定等待连接的客户数(目前最大值为5最小值为1)
------------------------------------------------------------------------------------------------------------------------------------------------------------------
6. accept (接受连接请求)原型如下
SOCKET accept (
SOCKET s,
struct sockaddr FAR addr,
int FAR addrlen
);
Delphi中定义如下:
function accept(s: TSocket; addr: PSockAddr; addrlen: PInteger): TSocket; stdcall;
服务端程序用此函数来接受客户端的socket请求,accpet的返回值是一个新的socket套接字,用这个新的套接字来与当前连接的客户端通信,以前的socket套接字还会保留用来与其它客户端连接.
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
7. recv(接收信息)原型如下:
int recv (
SOCKET s,
char FAR buf,
int len,
int flags
);
Delphi定义如下:
function recv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
此函数用于面向连接的Socket中,以便能从另一端接收信息.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
8.Send(发送信息)原型如下:
int send (
SOCKET s
const char FAR* buf,
int len,
int flags
);
Delphi中定义如下 :
function send(s: TSocket; const Buf; len, flags: Integer): Integer; stdcall;
此函数用于面向连接的Socket中,以便于能发送信息到另一端.
———————————————————————————————————————————————————————————————————————————————————————-.
以上8个是Windows Socket 编程主要的几个函数, 慢慢学习慢慢消化吧.