Socket编程与示例

往期精选(欢迎转发~~)

1.Socket简介
  网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。
  Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原意那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务,几个定义:
(1)IP地址:即依照TCP/IP协议分配给本地主机的网络地址,两个进程要通讯,任一进程首先要知道通讯对方的位置,即对方的IP。
(2)端口号:用来辨别本地通讯进程,一个本地的进程在通讯时均会占用一个端口号,不同的进程端口号不同,因此在通讯前必须要分配一个没有被访问的端口号。
(3)连接:指两个进程间的通讯链路。
(4)半相关:网络中用一个三元组可以在全局唯一标志一个进程:(协议,本地地址,本地端口号),这样一个三元组,叫做一个半相关,它指定连接的每半部分。
(5)全相关:一个完整的网间进程通信需要由两个进程组成,并且只能使用同一种高层协议。也就是说,不可能通信的一端用TCP协议,而另一端用UDP协议。因此一个完整的网间通信需要一个五元组来标识:(协议,本地地址,本地端口号,远地地址,远地端口号),这样一个五元组,叫做一个相关(association),即两个协议相同的半相关才能组合成一个合适的相关,或完全指定组成一连接。

2.客户/服务器模式
  在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户/服务器(Client/Server, C/S)模式,即客户向服务器发出服务请求,服务器接收到请求后,提供相应的服务。客户/服务器模式的建立基于以下两点:
(1)首先,建立网络的起因是网络中软硬件资源、运算能力和信息不均等,需要共享,从而造就拥有众多资源的主机提供服务,资源较少的客户请求服务这一非对等作用。
(2)其次,网间进程通信完全是异步的,相互通信的进程间既不存在父子关系,又不共享内存缓冲区,因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步,这就是基于客户/服务器模式的TCP/IP。
服务器端:
其过程是首先服务器方要先启动,并根据请求提供相应服务:
(1)打开一通信通道并告知本地主机,它愿意在某一公认地址上的某端口(如FTP的端口可能为21)接收客户请求;
(2)等待客户请求到达该端口;
(3)接收到客户端的服务请求时,处理该请求并发送应答信号。接收到并发服务请求,要激活一新进程来处理这个客户请求(如UNIX系统中用fork、exec)。新进程处理此客户请求,并不需要对其它请求作出应答。服务完成后,关闭此新进程与客户的通信链路,并终止。
(4)返回第(2)步,等待另一客户请求。
(5)关闭服务器
客户端:
(1)打开一通信通道,并连接到服务器所在主机的特定端口;
(2)向服务器发服务请求报文,等待并接收应答;继续提出请求…
(3)请求结束后关闭通信通道并终止。
从上面所描述过程可知:
(1)客户与服务器进程的作用是非对称的,因此代码不同。
(2)服务器进程一般是先启动的。只要系统运行,该服务进程一直存在,直到正常或强迫终止。

3.API函数
创建套接字──socket()
指定本地地址──bind()
建立套接字连接──connect()与accept()
监听连接──listen()
数据传输──send()与recv()
输入/输出多路复用──select()
关闭套接字──closesocket()

4.示例
流程图:
这里写图片描述
服务器代码:

#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);
}

参考: http://blog.csdn.net/wind19/article/details/6156339

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值