linux c socket之通用socket,支持ipv4和ipv6

来源:互联网 发布:商品销售记账软件 编辑:程序博客网 时间:2024/05/18 20:46
/*  * File:   TCPEchoClient.c * Author: 云守护  通用客户端 * * Created on 2013年11月13日, 下午3:49 */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <netinet/in.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netdb.h>#include "DieWithMessage.h"//建立客户端socketint SetupTCPClientSocket(const char *host,const char* service){    //配置想要的地址信息    struct addrinfo addrCriteria;    memset(&addrCriteria,0,sizeof(addrCriteria));    addrCriteria.ai_family=AF_UNSPEC;    addrCriteria.ai_socktype=SOCK_STREAM;    addrCriteria.ai_protocol=IPPROTO_TCP;        struct addrinfo *server_addr;    //获取地址信息    int retVal=getaddrinfo(host,service,&addrCriteria,&server_addr);    if(retVal!=0)        DieWithUserMessage("getaddrinfo() failed!",gai_strerror(retVal));    int sock=-1;    struct addrinfo *addr=server_addr;    while(addr!=NULL)    {        //建立socket        sock=socket(addr->ai_family,addr->ai_socktype,addr->ai_protocol);        if(sock<0)            continue;        if(connect(sock,addr->ai_addr,addr->ai_addrlen)==0)        {            //链接成功,就中断循环            break;        }        //没有链接成功,就继续尝试下一个        close(sock);        sock=-1;        addr=addr->ai_next;    }    freeaddrinfo(server_addr);    return sock;}int main(int argc, char** argv) {    if(argc<3||argc>4)    {        DieWithUserMessage("param","<server addree/Name> <Echo Word> [<Server Port/Service>]");                 }    char *server=argv[1];    char* echoString=argv[2];    char * service=(argc==4)?argv[3]:"echo";    //建立链接    int sock=SetupTCPClientSocket(server,service);    if(sock<0)        DieWithUserMessage("SetupTCPClientSocket failed!","Unable to connect");    size_t echoStringLen=strlen(echoString);    //发送数据    ssize_t numBytes=send(sock,echoString,echoStringLen,0);    if(numBytes<0)        DieWithSystemMessage("send() failed!");    else if(numBytes!=echoStringLen)    {        DieWithUserMessage("send() ","sent unexpected number of bytes");          }    unsigned int totalBytesRcvd=0;    fputs("Received:",stdout);    while(totalBytesRcvd<echoStringLen)    {        char buffer[BUFSIZ];         //接收数据        numBytes=recv(sock,buffer,BUFSIZ-1,0);        if(numBytes<0)            DieWithSystemMessage("recv() failed!");        else if(numBytes==0)        {            DieWithUserMessage("recv()","connection closed prematurely");                 }        totalBytesRcvd+=numBytes;        buffer[numBytes]='\0';        //打印到控制台        fputs(buffer,stdout);            }    fputc('\n',stdout);    close(sock);      return (EXIT_SUCCESS);}
/*  * File:   TCPEchoServer.c 通用服务端 * Author: 云守护 * Created on 2013年11月14日, 上午10:10 */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <netdb.h>#include "DieWithMessage.h"void PrintSocketAddress(const struct sockaddr *address, FILE *stream) {  // Test for address and stream  if (address == NULL || stream == NULL)    return;  void *numericAddress; // Pointer to binary address  // Buffer to contain result (IPv6 sufficient to hold IPv4)  char addrBuffer[INET6_ADDRSTRLEN];  in_port_t port; // Port to print  // Set pointer to address based on address family  switch (address->sa_family) {  case AF_INET:    numericAddress = &((struct sockaddr_in *) address)->sin_addr;    port = ntohs(((struct sockaddr_in *) address)->sin_port);    break;  case AF_INET6:    numericAddress = &((struct sockaddr_in6 *) address)->sin6_addr;    port = ntohs(((struct sockaddr_in6 *) address)->sin6_port);    break;  default:    fputs("[unknown type]", stream);    // Unhandled type    return;  }  // Convert binary to printable address  if (inet_ntop(address->sa_family, numericAddress, addrBuffer,      sizeof(addrBuffer)) == NULL)    fputs("[invalid address]", stream); // Unable to convert  else {    fprintf(stream, "%s", addrBuffer);    if (port != 0)                // Zero not valid in any socket addr      fprintf(stream, "-%u", port);  }}static const int MAXPENDING=5;int SetupTCPServerSocket(const char *service){    //配置地址信息     struct addrinfo addrCriteria;    memset(&addrCriteria,0,sizeof(addrCriteria));    addrCriteria.ai_family=AF_UNSPEC;    addrCriteria.ai_flags=AI_PASSIVE;    addrCriteria.ai_socktype=SOCK_STREAM;    addrCriteria.ai_protocol=IPPROTO_TCP;        struct addrinfo *server_addr;    //获取地址信息    int retVal=getaddrinfo(NULL,service ,&addrCriteria,&server_addr);    if(retVal!=0)        DieWithUserMessage("getaddrinfo failed!",gai_strerror(retVal));    int server_sock=-1;    struct addrinfo *addr=server_addr;    while(addr!=NULL)    {        //建立socket        server_sock=socket(server_addr->ai_family,server_addr->ai_socktype,server_addr->ai_protocol);        if(server_sock<0)            continue;        //绑定端口和监听端口        if((bind(server_sock,server_addr->ai_addr,server_addr->ai_addrlen)==0)&& listen(server_sock,MAXPENDING)==0)        {            struct sockaddr_storage local_addr;            socklen_t addr_size=sizeof(local_addr);            if(getsockname(server_sock,(struct sockaddr *)&local_addr,&addr_size)<0)            {                DieWithSystemMessage("getsockname() failed!");            }            fputs("Binding to ",stdout);            PrintSocketAddress((struct sockaddr*)&local_addr,stdout);            fputc('\n',stdout);            break;               }        close(server_sock);        server_sock=-1;        addr=addr->ai_next;    }    freeaddrinfo(server_addr);    return server_sock;  }void HandleTCPClient(int clntSocket) {  char buffer[BUFSIZ]; // Buffer for echo string  // Receive message from client  ssize_t numBytesRcvd = recv(clntSocket, buffer, BUFSIZ, 0);  if (numBytesRcvd < 0)    DieWithSystemMessage("recv() failed");  // Send received string and receive again until end of stream  while (numBytesRcvd > 0) { // 0 indicates end of stream    // Echo message back to client    ssize_t numBytesSent = send(clntSocket, buffer, numBytesRcvd, 0);    if (numBytesSent < 0)      DieWithSystemMessage("send() failed");    else if (numBytesSent != numBytesRcvd)      DieWithUserMessage("send()", "sent unexpected number of bytes");    // See if there is more data to receive    numBytesRcvd = recv(clntSocket, buffer, BUFSIZ, 0);    if (numBytesRcvd < 0)      DieWithSystemMessage("recv() failed");  }  close(clntSocket); // Close client socket}int acceptTCPConnection(int server_sock){    struct sockaddr_storage client_addr;    socklen_t client_addrLen=sizeof(client_addr);    int client_sock=accept(server_sock,(struct sockaddr *)&client_addr,&client_addrLen);    if(client_sock<0)        DieWithSystemMessage("accept() failed!");    fputs("Handing client ",stdout);    PrintSocketAddress((struct sockaddr*)&client_addr,stdout);    fputc('\n',stdout);    return client_sock;}int main(int argc, char** argv) {    if(argc!=2)        DieWithUserMessage("param","<server Port/Service>");    char * service=argv[1];    int server_sock=SetupTCPServerSocket(service);    if(server_sock<0)    {        DieWithUserMessage("SetupTCPServerSocket() failed!",service);    }    for(;;)    {        int client_sock=acceptTCPConnection(server_sock);        HandleTCPClient(client_sock);        close(client_sock);    }                return (EXIT_SUCCESS);}
/*  * File:   DieWithMessage.h * Author: root * * Created on 2013年11月13日, 下午3:52 */#ifndef DIEWITHMESSAGE_H#defineDIEWITHMESSAGE_H#ifdef__cplusplusextern "C" {#endif#include <stdio.h>#include <stdlib.h> void  DieWithUserMessage(const char *msg,const char * detail) {     fputs(msg,stderr);     fputs(":",stderr);     fputs(detail,stderr);     fputs("\n",stderr);     exit(1); } void DieWithSystemMessage(const char* msg) {     perror(msg);     exit(1); }#ifdef__cplusplus}#endif#endif/* DIEWITHMESSAGE_H */



原创粉丝点击