用VC实现Winsock中Server和Client 之间的通信。
Winsock中用于网络编程的几个函数功能介绍:
int WSAStartup( WORD v , (LPWSADATA) &WD ) ; //用于初始化Winsock
void WSACleanup( ) ; //关闭Winsock
void closesocket( SOCKET s ) ;
Winsock 的建立和撤销函数
创建套接字:API 是建立在套接字概念上的,套接字是传输层提供程序的句柄,是SOCKET类型,用socket创建套接字
SOCKET socket(int af, int type, int protocol);
其中:af表示协议族,
af = AF_INET :TCP/IP地址;
af = AF_UNIX :UNIX地址;
type表示协议的套接字类型
type = SOCK_STREAM : TCP协议
type = SOCK_DGRAM : UDP协议
protocol : 依赖于type参数,表示使用的协议
protocol = IPPROC_TCP : TCP ;
Protocol = IPPROC_UDP :UDP ;
protocol = 0 : 默认;
struct sockaddr_in{
short sin_family ; //告诉Winsock使用的IP地址族
u_short sin_port ; //16位端口号 , 网络字节顺序
struct in_addr sin_addr ; //32位IP地址,网络字节顺序
char sin_zero[8] ; //填充项,是SOCKADDR_IN结构
}
struct in_addr {
u_long s_addr ; //32bit的IP地址,网络字节顺序
}
bind(SOCKET s,(SOCKADDR *)&addr , sizeof(SOCKADDR));
int listen(SOCKET s , int backlog); //backlog:表示被挂起的连接的队列的最大长度
SOCKET accept(SOCKET s, (SOCKADDR *)&addr,&sizeof(SOCKADDR)) ;
htonl:将按主机字节顺序排序的4字节数转化为按网络字节顺序排序的4字节数。
htons:将按主机字节顺序排序的2字节数转化为按网络字节顺序排序的2字节数。
inet_addr函数把一个点分IP 地址转换成按网络字节顺序排列的32位无符号长整数
客户机端的函数设置,和服务器端的类似,也是建立一个SOCKET ,然后用一个SOCKADDR_IN结构初始化要通信的服务器的地址结构信息。这个需要注意的一点就是客户机端一般不需要bind,客户机端的bind由操作系统自行完成。 接着就是向服务器发出一个connect连接请求,为:
int connect(SOCKET s , (SOCKADDR *)&addr,sizeof(SOCKADDR)) ;
待服务器和客户机之间的连接建立之后,就可以用send().recv()函数进行通信了
//面向连接的发送接收函数
int send(SOCKET s,const char *buf , int len , int flag) //flag一般= 0
int recv(SOCKET s, const char *buf, int len , int flag)
//面向无连接的发送和接收函数:
int recvfrom(SOCKET s,char *buf, int len, int flag,(SOCKADDR *)&addr,sizeof(SOCKADDR)) ; //其中addr用以存放操作的另外一方的地址信息
int sendto(SOCKET s ,char *buf, int len ,int flag, (SOCKADDR *)&addr,sizeof(SOCKADDR)) ; //其中的addr和上面的含义一样
服务器端代码:
/*
服务器端!
*/
#include<stdio.h>
#include<winsock2.h>
#include<string.h>
#pragma comment(lib,"ws2_32.lib") //添加"winsock2.h的库"
int main(){
WSADATA wsadata ;
if(WSAStartup(MAKEWORD(2,2),&wsadata)!=0){ //初始化Winsock
printf("初始化网络协议失败\n");
exit(1) ;
}
SOCKET s_socket = socket(AF_INET,SOCK_STREAM,0); //设定为TCP/IP协议,Socket类型为流式套接字
if(s_socket == INVALID_SOCKET){
printf("Faile to socket!\n");
exit(1) ;
}
SOCKADDR_IN A ; //设置服务器的地址结构
A.sin_family = AF_INET ;
A.sin_port = htons(1234);
A.sin_addr.S_un.S_addr = htonl(INADDR_ANY) ; //IP地址默认生成
bind(s_socket ,(SOCKADDR *)&A,sizeof(A)); //本地信息的绑定
listen(s_socket,5); //服务器进入监听状态
printf("Server is Waiting ...\n");
SOCKADDR_IN B ; //accept后存放客户机的本地地址结构
int len = sizeof(SOCKADDR) ;
SOCKET socket_conn = accept(s_socket,(SOCKADDR *)&B ,&len);
if(socket_conn != INVALID_SOCKET){
printf("正在进行通信!\n");
while(1){ //处于一直监听状态
char meg[80] ;
printf("输入所要传输的消息:");
fgets(meg,80,stdin); inet_ntoa(B.sin_addr); //将网络字IP装换成内存字IP
int len = strlen(meg);
if(meg[len-1] == '\n') meg[len-1] = 0 ;
send(socket_conn,meg,strlen(meg)+1,0); //发送
printf("已发送了%d个字符\n",strlen(meg)+1);
if(strcmp(meg,"quit") == 0){
printf("Server is cancelling the communication!\n");
break ;
}
char rev[80] ;
recv(socket_conn,rev,80,0); //接收
printf("已经接收到了%d个字符%s\n",strlen(rev)+1,rev);
if(strcmp(rev,"quit")==0){
printf("Client is cancelling the communication!\n");
break ;
}
}
closesocket(socket_conn) ; //关闭客户机的套接字连接
}
else{
printf("Faile to aceept!\n");
}
closesocket(s_socket); //关闭服务器的套接字
WSACleanup(); //关闭Winsock
return 0;
}
客户机端的代码:
/*
客户端!
*/
#include<stdio.h>
#include<string>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //添加包含"winsock2.h的库"
int main(){
WSADATA wsadata ;
if(WSAStartup(MAKEWORD(2,2),&wsadata)!=0){ //Winsock的初始化,应用的是2.2的版本
printf("Client 初始化失败!\n");
exit(1) ;
}
SOCKET c_socket = socket(AF_INET,SOCK_STREAM,0); //创建客户端的套接字
//此处省略了c_socket套接字的bind()操作,由操作系统自动完成绑定
SOCKADDR_IN A ; //设置与之通信的服务器端的套接字的地址结构的相关属性
A.sin_family = AF_INET ;
A.sin_port = htons(1234); //端口号
A.sin_addr.S_un.S_addr = inet_addr("222.247.149.234") ; //服务器的IP地址,根据自行需要设置即可
int conn = connect(c_socket,(SOCKADDR *)&A,sizeof(SOCKADDR)); //与服务器建立连接
if(conn != WSAEADDRNOTAVAIL){
printf("正在与服务器进行通话!\n");
while(1){
char rev[80] ;
recv(c_socket,rev,80,0); //接收信息
printf("已经接收了%d个字符: %s\n",strlen(rev)+1,rev);
if(strcmp(rev,"quit") == 0){
printf("Server is Cancelling the communication!\n");
break ;
}
char buf[80] ;
fgets(buf,80,stdin);
int len = strlen(buf) ;
if(buf[len-1] == '\n') buf[len-1] = 0 ;
send(c_socket,buf,strlen(buf)+1,0); //发送信息
printf("已发送了%d个字符!\n",strlen(buf)+1);
if(strcmp(buf,"quit") == 0){
printf("Client is Cancelling the communication!\n");
break ;
}
}
printf("Communication is Done!\n");
}
else{
printf("Faile to connet\n");
exit(1) ;
}
closesocket(c_socket); //关闭客户端的套接字
WSACleanup() ; //终止对Winsock库的使用
return 0;
}