设为首页 | 加入收藏
您现在的位置: 唯才教育网 >> 电脑频道 >> c/c++ >> 使用c标准库编写网络程序

使用c标准库编写网络程序

作者:佚名    来源:网友投稿    点击数:    更新时间:

   mfc类库为我们提供了“方便、好用”的casyncsocket和csocket,但是mfc本身就是一个迷宫,进去一不小心就出不来了。像casyncsocket和csocket它们是实现是很复杂的,里面实现异步消息是通过窗体的消息机制来实现的,常常出现初始化时的错误,即使运行一段时间程序也常常出现莫名其妙的错误导致程序崩溃。你不要以为是mfc的问题,mfc是绝对不会承认的,有时候你不得不采用逐行注释代码的方法来确定什么地方导致程序的错误,这个过程是相当痛苦的,最后你还得为错误买单,肯定是你编程的错误,但你又不知道错在哪儿。
我有一次编写录音功能的网络程序,接收到远程录音传输的数据保存在内存中,后来发现程序不定时的在启动的时候调用csocket.create出错。程序都了n遍也不知道为什么,关键是不定时的,调试也麻烦,最后只好采用注释的方式。最终发现接收到录音数据保存到内容那段代码注释掉就好了,我认真看了那段代码,绝对没有内存溢出会导致覆盖掉csocket,每次接收数据总和也不会超过1m,不可能把内容耗尽。其实很多很成熟的软件都有类似的错误,老版本的迅雷也曾经出现过这种错误,错误的提示我忘了。
用了一年的casyncsocket后,我下了决心以后决不用它了,当然也不会用从它继承而来的csocket。那就用c标准库的socket,什么操作和错误都是掌握在自己的手中。没有了casyncsocket的异步消息机制自己用线程来做,网络编程多线程是第一课。
经过长期的实贱,封装了如下socket函数,其实使用也挺简单的:

1。客户端函数:
#include<stdlib.h>
#include<winsock.h>
#include<stdio.h>
#include<string.h>

#ifndef inaddr_none
#define inaddr_none 0xffffffff
#endif

//******************************************************
//
//本函数负责与服务平台联系
//
//******************************************************

socket socketconnect(const char *host,const char *service,const char *transport)
{
struct protoent *protoin;//传输协议信息
struct sockaddr_in ipaddr;//主机的ip地址信息
struct hostent *hostin;//主机的信息
struct servent *servin;//服务器(主机)信息
int sock,type;//套接字描述符

//将ipaddr结构快速清零
memset(&ipaddr,0,sizeof(ipaddr));
//地址结构
ipaddr.sin_family=af_inet;

//从服务器类型得到端口号
if(servin=getservbyname(service,transport))
ipaddr.sin_port=servin->s_port;//端口号
else
if((ipaddr.sin_port=htons((u_short)atoi(service)))==0)
{
printf("get server information error\n");
wsacleanup();
return invalid_socket;
}
//由传输协议得到对应的传输协议编码
if((protoin=getprotobyname(transport))==0)
{
printf("get protocol information error\n");
wsacleanup();
return invalid_socket;
}
//从主机名获取主机ip
if(hostin=gethostbyname(host))
memcpy(&ipaddr.sin_addr,hostin->h_addr,hostin->h_length);////
else
if((ipaddr.sin_addr.s_addr=inet_addr(host))==inaddr_none)
{
printf("get host ip infomation error\n");
wsacleanup();
return invalid_socket;
}
//根据传输类型给变量赋值
if(strcmp(transport,"udp")==0)
type=sock_dgram;
else
type=sock_stream;
//创建套接字描述符
sock=socket(pf_inet,type,protoin->p_proto);
if(sock==invalid_socket)
{
printf("creat socket error\n");
wsacleanup();
return invalid_socket;
}

//连接指定ip地址机器的指定服务端口,如果连接失败,则退出
if(connect(sock,(struct sockaddr*)&ipaddr,sizeof(ipaddr))==socket_error)
{
printf("connect socket error!please start server first\n");
wsacleanup();
return invalid_socket;
}
return sock;
}

//************************************
//udp传输类型
//************************************
socket udpconnect(const char *host,const char *service)
{
return socketconnect(host,service,"udp");
}

//************************************
//tcp传输类型
//************************************
socket tcpconnect(const char *host,const char *service)
{
return socketconnect(host,service,"tcp");
}

2。客户端函数调用例子(tcp):
//启动程序后即连接服务器,连接成功后接收控制台输入,发送到服务端
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<winsock.h>
#include"socketconnect.h"
#include"sendingcontrol.h"
#pragma comment(lib,"wsock32")

#ifndef inaddr_none
#define inaddr_none 0xffffffff
#endif

socket tcpconnect(const char*,const char*);
void tcpecho(char *,char*);

#define linelen 128
#define wavers makeword(2,0)//word makeword(byte blow,byte bhigh);

void main(int argc,char *argv[])
{
char *host="localhost";//ip 地址
char *service="3333";//默认端口号
wsadata wsadata;
switch(argc)
{
case 1:
host="localhost";//使用默认ip
break;
case 2:
host=argv[1];//使用命令行给的ip
break;
case 3:
host=argv[1];
service=argv[2];//使用命令行ip和端口号
break;
default:
printf("argment error\n");
exit(1);
}
if(wsastartup(wavers,&wsadata)!=0)//初始化winsock
{
printf("initalize failed\n");
wsacleanup();//清除winsock
exit(1);
}
tcpecho(host,service);
wsacleanup();
exit(0);
}

void tcpecho(char *host,char *service)
{
char buf[linelen+1];
socket s;
int outchars;

s=tcpconnect(host,service);//采用tcp协议连接服务程序
while(fgets(buf,sizeof(buf),stdin))//循环调用得到用户输入,当输入的数据为回车时退出
{
buf[linelen]='\0';
outchars=strlen(buf);
send(s,buf,outchars,0);//发送消息

if(buf[0]=='\n')
break;
}
closesocket(s);
}

3。服务端函数:
#include<string.h>
#include<winsock.h>
#include<stdlib.h>
#include<stdio.h>
//
//socketserver
//
socket socketserver(const char *service,const char*transport,int qlen)
{
struct sockaddr_in ipaddr;//主机ip地址
struct servent *servin;// 主机信息
struct protoent *protoin;//传输类型
int sock,type;// 套接字描述符

memset(&ipaddr,0,sizeof(ipaddr));
ipaddr.sin_family=af_inet;
ipaddr.sin_addr.s_addr=inaddr_any;

// 从服务器名得到服务端口
if(servin=getservbyname(service,transport))
ipaddr.sin_port=htons(ntohs((u_short)servin->s_port));
else
if((ipaddr.sin_port=htons((u_short)atoi(service)))==0)
{
printf("get portnumber error\n");
wsacleanup();
return invalid_socket;
}
//从传输协议得到对应的编号
if((protoin=getprotobyname(transport))==0)
{
printf("get protocol number error\n");
wsacleanup();
return invalid_socket;
}
//根据传输协议给对应的变量赋值
if(strcmp(transport,"udp")==0)
type=sock_dgram;
else
type=sock_stream;
//创建套接字
sock=socket(pf_inet,type,protoin->p_proto);
if(sock==invalid_socket)
{
printf("creat socket error\n");
wsacleanup();
return invalid_socket;
}
//绑定本地ip
if(bind(sock,(struct sockaddr*)&ipaddr,sizeof(ipaddr))==socket_error)
{
printf("socket bind error\n");
wsacleanup();
return socket_error;
}
//如果是流式传输(tcp)使套接字处于监听状态,等待来自客户机的连接,参数qlen之指定等待
//队列长度
if(type==sock_stream)
{
if(listen(sock,qlen)==socket_error)
{
printf("socket listen errror\n");
wsacleanup();
return socket_error;
}
}
return sock;
}


//************************************
//udpserver
//************************************
socket udpserver(const char *service)
{
return socketserver(service,"udp",0);
}

//************************************
//tcpserver
//************************************
socket tcpserver(const char *service,int qlen)
{
return socketserver(service,"tcp",qlen);
}

4。服务器例子(tcp):
//接受客户端连接,每接收到客户端发送而来的数据则打印在控制台
#include<winsock.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include"socketserver.h"
#pragma comment(lib,"wsock32")

#define qlen 5
#define bufsize 5
#define wavers makeword(2,0)//word makeword(byte blow,byte bhigh);

socket tcpserver(const char*service,int qlen);
void main(int argc,char*argv[])
{
char *service="3333";//默认端口号
struct sockaddr_in fsin;
socket msock,ssock;
wsadata wsadata;
int alen,cc;
char buf[bufsize];

switch(argc)
{
case 1:
break;//采用默认端口号
case 2:
service=argv[1];//采用命令行端口号
break;
default:
printf("argment error\n");
exit(1);
}
if(wsastartup(wavers,&wsadata)!=0)//初始化winsock
{
printf("initalize failed\n");
wsacleanup();//清除winsock
exit(1);
}

msock=tcpserver(service,qlen);//采用tcp协议

while(1)
{
alen=sizeof(struct sockaddr);
ssock=accept(msock,(struct sockaddr*)&fsin,&alen);//accept阻塞接收客户端请求

if(ssock==invalid_socket)
{
printf("initialize failed\n");
wsacleanup();
exit(1);
}
while(cc=recv(ssock,buf,sizeof(buf)-1,0))//接收客户端信息,当收到的信息为零时,则退出
{
buf[cc]='\0';
printf("%s",buf);
}
printf("connect close...");
closesocket(ssock);
break;
}
}

以上是两个完整的客户端和服务端程序,可建立两个vc控制台工程编译运行,进行连接测试。

查看和“c/c++”有关的所有文章


  • 上一篇文章:

  • 下一篇文章: