Linux下(c++)实现socket(一)

                                     Linux下实现socket(c++)

    近期学习了linux下的简单socket编程,在这里与大家分享一下,有疑问或者错误欢迎大家讨论和指出.     

socket是什么? 

          Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。即Socket提供了操作上述特殊文件的接口.使用这些接口可以实现网络编程。
                   
                           Linux下(c++)实现socket(一)
        流程图
TCP和UDP

        TCP(Transmission Control Protocol,传输控制协议是面向连接的协议,在正式通信之前必须建立起连接。UDP(User Data Protocol,用户数据报协议)是一个非连接的协议。因此TCP的服务器模式比UDP的服务器模式多了listen,accept函数。TCP客户端比UDP客户端多了connect函数。这里着重介绍TCP下socket简单编程.

TCP使用socket创建服务器端一般步骤是:

1、创建一个socket,用函数socket();

2、绑定IP地址、端口等信息到socket上,用函数bind();

3、开启监听,用函数listen();

4、接收客户端上来的连接,用函数accept();

5、收发数据,用函数send()和recv(),或者read()和write();

6、关闭网络连接;

7、关闭监听;

TCP使用socket创建

Client端一般步骤是:

TCP使用socket创建客户端一般步骤是:

1、创建一个socket,用函数socket();

2、连接服务器,用函数connect();

3、收发数据,用函数send()和recv(),或者read()和write();

4、关闭网络连接;

client端程序的具体实现:

需要完成的任务

  • 创建嵌套字( socket() )
  • 向服务器发送连接请求( connect() )
  • 和服务器进行通信( send()/recv() )
  • 关闭嵌套字( close() )

函数使用说明

1.socket()

    需要的头文件

      #include <sys/types.h> /* See NOTES */
      #include <sys/socket.h>
      声明

      int socket(int domain, int type, int protocol);

    参数说明:

   (1) domain:

Name    Purpose    Man page
AF_UNIX, AF_LOCAL     Local communication    unix(7)
AF_INET    IPv4 Internet protocols    ip(7)
AF_INET6    IPv6 Internet protocols    ipv6(7)
AF_IPX    IPX - Novell protocols    
AF_NETLINK     Kernel user interface device    netlink(7)
AF_X25    ITU-T X.25 / ISO-8208 protocol    x25(7)
AF_AX25     Amateur radio AX.25 protocol    
AF_ATMPVC    Access to raw ATM PVCs    
AF_APPLETALK    AppleTalk    ddp(7)
AF_PACKET     Low level packet interface    packet(7)
AF_ALG     Interface to kernel crypto API   

    (2)type

The socket has the indicated type, which specifies the communication semantics. Currently defined types are:
SOCK_STREAM
Provides sequenced, reliable, two-way, connection-based byte streams. An out-of-band data transmission mechanism may be supported.//提供顺序、可靠、双向、基于连接的字节流。可支持带外数据传输机制.tcp是需要连接的,udp不需要连接.
SOCK_DGRAM
Supports datagrams (connectionless, unreliable messages of a fixed maximum length).
SOCK_SEQPACKET
Provides a sequenced, reliable, two-way connection-based data transmission path for datagrams of fixed maximum length; a consumer is required to read an entire packet with each input system call.
SOCK_RAW
Provides raw network protocol access.
SOCK_RDM
Provides a reliable datagram layer that does not guarantee ordering.
SOCK_PACKET
Obsolete and should not be used in new programs; see packet(7).

(3)protocol(协议)

protocol:指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。

(4)RETURN VALUE
On success, a file descriptor for the new socket is returned. On error, -1 is returned, and errno is set appropriately.//如果创建错误,将返回-1

2.connec( sockfd, addr, addrlen):返回值为-1时连接失败

(1)声明和头文件
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    int connect(int sockfd, const struct sockaddr *addr,
            socklen_t addrlen);

addr:连接目标服务器的协议族。

addr_len:对应的地址的长度。

如果连接或绑定成功, 则返回零。错误时, 返回-1
3.和服务器进行通信( send()/recv() )
(1)#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
用于从socket接受消息,

不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。

该函数的第一个参数指定接收端套接字描述符;

第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;

第三个参数指明buf的长度;

第四个参数一般置0。

4.send

int send( SOCKET s,      const char FAR *buf,      int len,      int flags );  
不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。

客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。

该函数的第一个参数指定发送端套接字描述符;

第二个参数指明一个存放应用程序要发送数据的缓冲区;

第三个参数指明实际要发送的数据的字节数;

第四个参数一般置0。

client端程序代码:此处服务器ip用的是我阿里云的,端口80,读者可以在terminal运行时输入你要访问的ip和端口.

#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>

using namespace std;
int main(int argc,char **argv)
{
  int client, server;
// int portNum ; // note the server and clients Ip are the same
  bool isExit = false;
  int bufsize = 1024;
  char buffer[bufsize];
 // char *ip = "182.254.18.159";
  struct sockaddr_in server_addr;
  if(argc != 3)
  {
    cout<<"usesge:socket_client ipaddress poet.  client 182.154.18.159 80 "<<endl;
  }
  int portNum = atoi(argv[2]);//端口号
  //init socket
  client = socket(AF_INET,SOCK_STREAM,0);
  if(client < 0)
  {
    cout<<"Error creating socket"<<endl;
    exit(1);
  }
 
  cout<<"socket client have been created test"<<endl;
  server_addr.sin_port = htons(portNum);
  server_addr.sin_family = AF_INET;
   server_addr.sin_addr.s_addr = inet_addr(argv[1]);//inet_addr () 函数将 Internet 主机地址 cp 从 IPv4 数字和点符号转换为网络字节顺序中的二进制数据。
  // connecting socket server
 
  if (connect(client,(struct sockaddr*)&server_addr,sizeof(server_addr)) == 0)
    cout<<"connecting to server"<<endl;
   
  recv(client,buffer,bufsize,0);
  cout<<"connection confirmed"<<endl;
  cout<< "enter # to end the connect"<<endl;
 
do{
    cout<<"client:";
    do{
      cin>> buffer;
      send(client,buffer,bufsize,0);
   if(*buffer == '#')
      {
      send(client,buffer,bufsize,0);
      *buffer = '*';
      isExit = true;
      }
      *
    }while(*buffer != 42);
    cout<<"server: ";
    
    do{
      recv(client,buffer,bufsize,0);
      cout<<buffer<<"";
     if(*buffer == '#')
      {
    *buffer = '*';
    isExit = true;
      }  
    }while(*buffer !=42);
    
    cout<<endl;
  }while(!isExit);

    cout<<"connection terminated ..."<<endl;
    cout<<"goodbye"<<endl;
    close(client);
    return 0;
  }