网络编程——简单客户端与服务器
1、网络编程一般思路
1.1-服务器创建流程:
第一步:
初始化套接字环境
第二步:
创建监听套接字,创建保存监听套接字的地址变量
第三步:
为监听套接字地址信息赋值
第四步:
将监听套接字根据其地址进行绑定
第五步:
进入监听状态,准备接受连接
第六步:
接受链接后处理连接
第七步:
关闭套接字,关闭资源
1.2-客户端创建流程:
流程跟服务器创建差不多
第一步:
初始化套接字环境
第二步:
创建客户端套接字,创建保存服务器地址信息的变量
第三步:
将服务器地址信息赋值给服务器地址变量
第四步:
根据服务器地址信息进行连接
第五步:
链接后处理连接(收发消息)
第六步:
关闭套接字,关闭资源
总结:服务器与客户端创建就像打电话
用户创建客户端电话机,知道服务器电话号吗,给服务器拨号,通啦后交流,最后挂断电话。
用户(是一个海王)创建服务器监听电话机,安排一个人专门去守着等着接电话,如果有人打电话来了,就将电话转给另一个电话机,他自己仍然坚守岗位,另一个用户就用另一个电话机和来点人员煲电话,最后海王不想谈了,就挂断所有电话,释放资源。
2、网络编程代码:
服务器:
#include<winsock2.h>
#include<stdio.h>
/*为了方便设置地址信息*/
void SetAddr(SOCKADDR_IN* ServerAddr,char* ip,int port) {
memset(ServerAddr, 0, sizeof(*ServerAddr)); //每个字节都用0填充
ServerAddr->sin_family = AF_INET; //使用IPv4地址
ServerAddr->sin_addr.s_addr = inet_addr(ip); //具体的IP地址
ServerAddr->sin_port = htons(port); //端口
}
int main() {
//初始化套接字资源
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
//创建服务器
SOCKET Server = socket(AF_INET, SOCK_STREAM, 0);
//设置服务器IP和端口
SOCKADDR_IN ServerAddr;
SetAddr(&ServerAddr,"127.0.0.1",8080);
//绑定IP和端口
bind(Server,(SOCKADDR*)&ServerAddr,sizeof(ServerAddr));
//监听
listen(Server,5);
//依据服务器接受连接请求
SOCKADDR_IN ClientAddr;int ClientAddrSize=sizeof(SOCKADDR_IN);
SOCKET Client = accept(Server,(SOCKADDR*)&ClientAddr,&ClientAddrSize);
//功能区 处理消息
printf("IP:%s\tPORT:%d\n",inet_ntoa(ClientAddr.sin_addr),ClientAddr.sin_port);
send(Client,"你好",5,0);
//资源释放
closesocket(Client);
closesocket(Server);
WSACleanup();
system("pause");
return 0;
}
客户端:
#include<winsock2.h>
#include<stdio.h>
/*为了方便设置地址信息*/
void SetAddr(SOCKADDR_IN* ServerAddr, char* ip, int port) {
memset(ServerAddr, 0, sizeof(*ServerAddr)); //每个字节都用0填充
ServerAddr->sin_family = AF_INET; //使用IPv4地址
ServerAddr->sin_addr.s_addr = inet_addr(ip); //具体的IP地址
ServerAddr->sin_port = htons(port); //端口
}
int main() {
//初始化套接字资源
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
//创建套接字
SOCKET Client = socket(AF_INET, SOCK_STREAM, 0);
//设置服务器地址
SOCKADDR_IN ServerAddr;
char ip[16]={0};printf("服务器IP地址:"),gets(ip);
SetAddr(&ServerAddr, ip, 8080);
//连接服务器
connect(Client, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr));
//操作
char buff[24];
recv(Client, buff, 24, 0);
puts(buff);
//关闭资源
closesocket(Client);
WSACleanup();
system("pause");
return 0;
}
//建立连接后,通信使用的函数
recv //接受消息
send //发送消息
recv()/send():
1)send函数:
send 的参数含义如下:
sockfd :代表你与远程程序连接的套接字描述符。
msg :一个指针,指向你想发送的信息的地址。
len :是你想发送信息的长度。
flags :发送标记。一般都设为0(你可以查看send 的man pages 来获得其他的参数值并且明白各个参数所代表的含义)。
2)send返回值:
send()函数在调用后会返回它真正发送数据的长度,send()函数如果发生错误,则返回 –1。
注意:
send所发送的数据可能少于你给它的参数所指定的长度!因为如果你给send()的参数中包含的数据的长度远远大于send()所能一次发送的数据,则send()函数只发送它所能发送的最大数据长度,然后它相信你会把剩下的数据再次调用它来进行第二次发送。所以,记住如果send()函数的返回值小于len 的话,则你需要再次发送剩下的数据。幸运的是,如果包足够小(小于1K),那么send()一般都会一次发送光的。
3)recv函数:
sockfd :是你要读取数据的套接字描述符。
buf :是一个指针,指向你能存储数据的内存缓存区域。
len :是缓存区的最大尺寸。
flags :是recv() 函数的一个标志,一般都为0 (具体的其他数值和含义请参考recv()
4)recv返回值:
recv() 返回它所真正收到的数据的长度。(也就是存到buf 中数据的长度)。如果返回–1 则代表发生了错误(比如网络以外中断、对方关闭了套接字连接等),全局变量errno 里面存储了错误代码。