socket编程——一个简单的例子

从一个简单的使用TCP例子开始socket编程,其基本步骤如下:

server                                                  client

+++++++                                          ++++++++

创建socket                                          创建socket

+++++++                                          ++++++++

|                                                         |

|                                                         |

|                                                         |

+++++++                                          ++++++++

地址赋值(                                           地址赋值(

自己的地址)                                        服务器地址)

+++++++                                          ++++++++

|                                                         |

|                                                         |

|                                                         |

++++++++                                              |

用bind绑定                                                |

socket和地址                                             |

++++++++                                              |

|                                                         |

|                                                         |

|                                                         |

+++++++                                                 |

listen                                                         |

+++++++                                                  |

|                                                    ++++++++++

|   <------------------------------          connect 服务器

|                                                    ++++++++++

+++++++                                                  |

accept                                                        |

+++++++                                                  |

|                                                           |

|                                                    +++++++++

|                                                     recv 和send

|                                                     进行数据处理

|                                                     +++++++++

+++++++++                                                |

用accept得到                                                 |

的socket进行                                                 |

recv 和 send                                                 |

+++++++++                                                |

|                                                             |

|                                                             |

|                                                             |

+++++++++                                        +++++++++

close socket                                         close socket

+++++++++                                        +++++++++

根据以上步骤,服务器端的代码为

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <syslog.h>
#include <errno.h>
#define MAX_LISTEN_NUM 5
#define SEND_BUF_SIZE 100
#define RECV_BUF_SIZE 100
#define LISTEN_PORT 1010
int main()
{
  int listen_sock = 0;
  int app_sock = 0;
  struct sockaddr_in hostaddr;
  struct sockaddr_in clientaddr;
  int socklen = sizeof(clientaddr);
  char sendbuf[SEND_BUF_SIZE] = {0};
  char recvbuf[RECV_BUF_SIZE] = {0};
  int sendlen = 0;
  int recvlen = 0;
  int retlen = 0;
  int leftlen = 0;
  char *ptr = NULL;
  memset((void *)&hostaddr, 0, sizeof(hostaddr));
  memset((void *)&clientaddr, 0, sizeof(clientaddr));
  hostaddr.sin_family = AF_INET;
  hostaddr.sin_port = htons(LISTEN_PORT);
  hostaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  listen_sock = socket(AF_INET, SOCK_STREAM, 0);
  if(listen_sock < 0)
  {
      syslog(LOG_ERR, "%s:%d, create socket failed", __FILE__, __LINE__);
      exit(1);
  }
  if(bind(listen_sock, (struct sockaddr *)&hostaddr, sizeof(hostaddr)) < 0)
  {
      syslog(LOG_ERR, "%s:%d, bind socket failed", __FILE__, __LINE__);
      exit(1);
  }
  if(listen(listen_sock, MAX_LISTEN_NUM) < 0)
  {
      syslog(LOG_ERR, "%s:%d, listen failed", __FILE__, __LINE__);
      exit(1);
  }
  while(1)
  {
      app_sock = accept(listen_sock, (struct sockaddr *)&clientaddr, &socklen);
      if(app_sock < 0)
     {
        syslog(LOG_ERR, "%s:%d, accept failed", __FILE__, __LINE__);
        exit(1);
     }
     sprintf(sendbuf, "welcome %s:%d here!/n", inet_ntoa(clientaddr.sin_addr.s_addr), clientaddr.sin_port);
     //send data
     sendlen = strlen(sendbuf) +1;
     retlen = 0;
     leftlen = sendlen;
     ptr = sendbuf;
     //while(leftlen)
     {
         retlen = send(app_sock, ptr, sendlen, 0);
      if(retlen < 0)
      {
          if(errno == EINTR)
            retlen = 0;
        else
            exit(1);
      }
      leftlen -= retlen;
      ptr += retlen;
     }
     //receive data
     recvlen = 0;
     retlen = 0;
     ptr = recvbuf;
     leftlen = RECV_BUF_SIZE -1;
     //do
     {
         retlen = recv(app_sock, ptr, leftlen, 0) ;
      if(retlen < 0)
      {
          if(errno == EINTR)
            retlen = 0;
        else
            exit(1);
      }
      recvlen += retlen;
      leftlen -= retlen;
      ptr += retlen;
     }
     //while(recvlen && leftlen);
     printf("receive data is : %s", recvbuf);
    close(app_sock);
  }
  close(listen_sock);  

  return 0;  

}  

客户端代码为:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <syslog.h>
#include <errno.h>
#include <stdlib.h>
#define MAX_LISTEN_NUM 5
#define SEND_BUF_SIZE 100
#define RECV_BUF_SIZE 100
#define SERVER_PORT 1010
int main()
{
    int sock_fd = 0;
    char recvbuf[RECV_BUF_SIZE] = {0};
    char sendbuf[SEND_BUF_SIZE] = {0};
    int recvlen = 0;
    int retlen = 0;
    int sendlen = 0;
    int leftlen = 0;
    char *ptr = NULL;
    struct sockaddr_in ser_addr;  

    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    inet_aton("127.0.0.1", (struct in_addr *)&ser_addr.sin_addr);
    ser_addr.sin_port = htons(SERVER_PORT);
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(sock_fd < 0)
    {
        syslog(LOG_ERR, "%s:%d, create socket failed", __FILE__, __LINE__);
        exit(1);
    }
    if(connect(sock_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr)) < 0)
    {
        syslog(LOG_ERR, "%s:%d, connect socket failed", __FILE__, __LINE__);
        exit(1);
    }
     //receive data
     recvlen = 0;
     retlen = 0;
     ptr = recvbuf;
     leftlen = RECV_BUF_SIZE -1;
     //do
     {
         retlen = recv(sock_fd, ptr, leftlen, 0) ;
      if(retlen < 0)
      {
          if(errno == EINTR)
            retlen = 0;
        else
            exit(1);
      }
      recvlen += retlen;
      leftlen -= retlen;
      ptr += retlen;
     }
     //while(recvlen && leftlen);
     printf("receive data is : %s", recvbuf);
     sprintf(sendbuf, "hello server/n");
     //send data
     sendlen = strlen(sendbuf) +1;
     retlen = 0;
     leftlen = sendlen;
     ptr = sendbuf;
    // while(leftlen)
     {
         retlen = send(sock_fd, ptr, sendlen, 0);
      if(retlen < 0)
      {
          if(errno == EINTR)
            retlen = 0;
        else
            exit(1);
      }
      leftlen -= retlen;
      ptr += retlen;
     }
     close(sock_fd);  

}  

现在一个简单的使用tcp的socket通信的例子已经完成了,这里有几个需要说明的问题

1)头文件:

sys/socket.h   包含了socket相关的函数,如socket,send 和recv, 以及struct sockaddr等

netinet/in.h    包含了地址结构,如struct sockaddr_in

errno.h           包含了errno 和 EINTR

syslog.h         包含了syslog相关的信息,其打印结果在/var/log/messages里面

2)socket地址

对于IPv4来说,其地址用的是struct sockaddr_in,具体结构如下

struct in_addr {
  in_addr_t   s_addr;           /* 32-bit IPv4 address */
                                /* network byte ordered */
};  

struct sockaddr_in {
  uint8_t         sin_len;      /* length of structure (16) */
  sa_family_t     sin_family;   /* AF_INET */
  in_port_t       sin_port;     /* 16-bit TCP or UDP port number */
                                /* network byte ordered */
  struct in_addr  sin_addr;     /* 32-bit IPv4 address */
                                /* network byte ordered */
  char            sin_zero[8];  /* unused */
};  
其中sin_len我们一般不关注,也不填(只有在使用routing socket的时候才用到,被内核用来处理各种协议簇的地址结构)。
bind, connect, sendto, 和 sendmsg会把socket地址从程序传递给内核; 而accept, recvfrom, recvmsg, getpeername, 和 getsockname会把地址从内核传递给程序。因为不同协议簇的地址结构是不一样的,所以必须要有一个通用的指针来传递地址,对于ANSI C来说我们一般使用void *,但是socket产生早于ANSI C,所以也就没有使用这个机制,而是使用一个通用的地址结构struct sockaddr来处理的
struct sockaddr {
  uint8_t      sa_len;
  sa_family_t  sa_family;    /* address family: AF_xxx value */
  char         sa_data[14];  /* protocol-specific address */
}; 
IPv6的socket地址为struct sockaddr_in6


struct in6_addr {
  uint8_t  s6_addr[16];          /* 128-bit IPv6 address */
                                 /* network byte ordered */
};  

#define SIN6_LEN      /* required for compile-time tests */  

struct sockaddr_in6 {
  uint8_t         sin6_len;      /* length of this struct (28) */
  sa_family_t     sin6_family;   /* AF_INET6 */
  in_port_t       sin6_port;     /* transport layer port# */
                                 /* network byte ordered */
  uint32_t        sin6_flowinfo; /* flow information, undefined */
  struct in6_addr sin6_addr;     /* IPv6 address */
                                 /* network byte ordered */
  uint32_t        sin6_scope_id; /* set of interfaces for a scope */
};  

对于sockaddr-in6来说,我们不能用通用的地址struct sockaddr来存储了,而是产用新的通用地址结构struct sockaddr_storage,这个结构足够大可以存储任何系统支持的地址。
struct sockaddr_storage {
  uint8_t      ss_len;       /* length of this struct (implementation dependent) */
  sa_family_t  ss_family;    /* address family: AF_xxx value */
  /* implementation-dependent elements to provide:
   * a) alignment sufficient to fulfill the alignment requirements of
   *    all socket address types that the system support
   * b) enough storage to hold any type of socket address that the
   *    system supports.
   */
};  
几种常见的地址结构
3) 相关函数的的length

对于从程序传地址给内核的函数(如connect),其长度是一个整型值,告诉内核要copy的地址长度。

对于从内核传递给程序的函数(如accpt),其长度是一个整型指针,是一个value-result参数。有两个目的:一告诉内核地址结构的长度,让内核在copy的时候不要超过这个长度;二返回内核真正copy的长度。
4)字节序
socket相关的函数都是使用网络字节序
5)地址转换函数
inet_aton, inet_ntoa, and inet_addr把IPv4字符串地址转为32位的网络字节序地址
inet_ptonand inet_ntop可以转换IPv4和IPv6的地址
6)listen中的backlog
要知道这个值的含义先用说一下,对于一个listen的socket,有两个队列:一个是incomplete connection队列(仅仅收到SYN);一个是complete connection队列(三次握手完成)。accept函数就是在complete connection队列中取一个socket。backlog就是指队列的个数,但不行的是各个地方都没有明确定义这个值,没有说明究竟代表了哪个队列,或是两个队列之和。一般来说可以
同时处理的连接数是backlog的1.5倍,很多地方都用5.
7) getsockname 和 getpeername
这两个函数可以与socket关联的地址,getsockname 和 getpeername分别得到自己和对端的地址
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen)  

int getpeername(int sockfd , struct sockaddr * peeraddr , socklen_t * addrlen );  

FROM: http://blog.csdn.net/wind19/article/details/6156339

时间: 2024-10-03 13:40:12

socket编程——一个简单的例子的相关文章

socket编程——一个简单的例子(转)

原文地址:http://blog.csdn.net/wind19/article/details/6156339 从一个简单的使用TCP例子开始socket编程,其基本步骤如下: server                                                  client +++++++                                          ++++++++ 创建socket                               

socket编程——一个简单的样例

从一个简单的使用TCP样例開始socket编程,其基本过程例如以下: server                                                  client +++++++                                          ++++++++ 创建socket                                          创建socket +++++++                            

socket计划——一个简单的例子

从一个简单易用TCP样品开始socket计划,的基本过程例如下列: server                                                  client +++++++                                          ++++++++ 创建socket                                          创建socket +++++++                             

socket编程---一个简单例子

服务器端代码(多线程): import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; public class MultiEchoServer { private static ServerSocket serverSocket; private static final int POR

[转] 3个学习Socket编程的简单例子:TCP Server/Client, Select

以前都是采用ACE的编写网络应用,最近由于工作需要,需要直接只用socket接口编写CS的代码,重新学习这方面的知识,给出自己所用到的3个简单例子,都是拷贝别人的程序.如果你能完全理解这3个例子,估计socket编程就已经基本入门了. 建议:1) 多多查查所用到的网络接口; 2) 最好有一本书,如UNIX环境高级编程,UNIX网络编程,可查询:3) 可以直接使用书上的例子更好. http://blog.csdn.net/zhenjing/article/details/4770490 TCP C

Swift和C混合Socket编程实现简单的ping命令

这个是用Mac下的Network Utility工具实现ping命令,用Wireshark抓取的ICMP数据包: 发送ICMP数据包内容 接受ICMP数据包内容 一.icmp结构 要真正了解ping命令实现原理,就要了解ping命令所使用到的TCP/IP协议.ICMP(Internet Control Message,网际控制报文协议)是为网关和目标主机而提供的一种差错控制机制,使它们在遇到差错时能把错误报告给报文源发方.ICMP协议是IP层的 一个协议,但是由于差错报告在发送给报文源发方时可能

【Python】一个简单的例子

问题描述: Python基础篇 参考资料: (1)http://www.cnblogs.com/octobershiner/archive/2012/12/04/2801670.html (2)http://www.cnblogs.com/itech/archive/2010/06/20/1760345.html 例子: 求解Fibonacci glb_var.py gl_count=1 path.py # coding:utf-8 ''' Created on 2014-4-28 @autho

socket编程,简单多线程服务端测试程序

socket编程,简单多线程服务端测试程序 前些天重温了MSDN关于socket编程的WSAStartup.WSACleanup.socket.closesocket.bind.listen.accept.recv.send等函数的介绍,今天写了一个CUI界面的测试程序(依赖MFC)作为补充.程序功能简介如下: 1:一个线程做监听用. 2:监听线程收到客户端连接后,创建新线程接收客户端数据.所有对客户端线程将加入容器,以便管理. 3:服务端打印所有客户端发来的信息. 4:服务端CUI界面输入数字

Linux下socket编程,附带tcp例子

1.网络中进程之间如何通信? 本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的和具名的) 远程过程调用(Solaris门和Sun RPC) 但这些都不是本文的主题!我们要讨论的是网络中进程之间如何通信?首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的.其实TCP/IP协议族已经帮我们解决了这个问