一、套接字(socket)

    套接字socket: ip地址 + port端口号。在TCP/IP协议中,它唯一标识网络通讯中的一个进程。

    在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socketpair就唯一标识一个连接。

    socket本身有“插座”的意思,因此用来描述网络连接的 一对一关系。


    TCP/IP协议规定,网络数据流应采用 大端字节序,即 (内存)低地址高字节(数据)。

 

二、TCP_SOCKET 相关

TCP 协议  ----  基于 字节流   ---  SOCK_STREAM 

IPv4地址格式定义在netinet/in.h中,IPv4地址: sockaddr_in结构体,包括16位端口号和32位IP地址

struct sockaddr_in
 {
    uint8_t sin_len;
    sa_family_t sin_family;
    in_port_t sin_port;
    struct in_addr sin_addr;
    char sin_zero[8];
};


h表示host,n表示network,l表示32位长整数,s表示16位短整数。

套接字编程 ---- TCP协议_第1张图片

#include  

#include

int socket(int domain, int type, int protocol); //创建套接字

    //domain: 底层通信所使用的协议   AF_INET(IPv4)、AF_INET6(IPv6)、AF_UNIX 

    //type: 协议实现的方式  SOCK_STREAM 有序的、可靠的、双向的和基于连接的字节流                      //protocol: 套接口所用的协议。前面两个参数设定后,这儿可用0指定,表示缺省。

返回值:成功 new socket的描述符,失败 -1


int bind(int sockfd, const struct sockaddr  *addr,socklen_t  addrlen);//绑定

int listen(int sockfd, int backlog); //监听 

     // sockfd:已经建立的socket编号(描述符)   SOCK_STREAM     SOCK_DGRAM

     // backlog: 连接请求队列的最大长度

返回值:成功 0,失败 -1


int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//阻塞等待

返回值:成功  非负整数的accept socket的描述符,失败 -1

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen); 

返回值:连接/绑定成功 0,失败 -1


#include

ssize_t write(int fd, const void *buf, size_t count); 

ssize_t read(int fd, void *buf, size_t count);


三、TCP协议 通讯流程

   1、服务器:调用socket()、bind()、listen() 完成初始化后,调用accept()阻塞等待,处于监听端口的状态。

      客户端:调用socket()初始化后,调用connect()发出SYN段并阻塞等待服务器应答,服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK段,服务器收到后从accept()返回。

   2、数据传输的过程

    建立连接后,TCP协议提供全双工的通信服务,但是一般的客户端/服务器程序的流程是由客户端主 动发起请求,服务器被动处理请求,一问一答的方式。因此,服务器从accept()返回后立刻调read(),socket就像读管道一样,如果没有数据到达就阻塞等待,这时客户端调用write()发送 请求给服务器,服务器收到后从read()返回,对客户端的请求进行处理,在此期间客户端调用read()阻塞等待服务器的应答,服务器调用write()将处理结果发回给客户端,再次调用read()阻塞等待下一条请求,客户端收到后从read()返回,发送下一条请求,如此循环下去。

    如果客户端没有更多的请求了,就调用close()关闭连接,就像写端关闭的管道一样,服务器的read()返回0,这样服务器就知道客户端关闭了连接,也调用close()关闭连接。注意,任何一方调用close()后,连接的两个传输方向都关闭,不能再发送数据了。如果一方调用shutdown()则连接处于半关闭状态,仍可接收对方发来的数据。

四、TCP socket API实例

//tcp_server.cpp

#include
using namespace std;

#include
#include
#include
#include
#include
#include
#include
#include
#include

const int g_backlog=5;


void usage(string _proc)
{
	cout<<"Usage:"<<_proc<<"[ip][port]"< 0)//read success
		{
			buf[_size] = '\0';
		}
		else if(_size == 0)//close connection
		{
			cout<<"client  close..."< 0)//read success
		{
			buf[_size] = '\0';
		}
		else if(_size == 0)//client close 
		{}
		else
		{
			cout< 0)//read success
			{
				buf[_size] = '\0';
			}
			else if(_size == 0)//client close 
			{
				cout<<_client<<"close..."< 
  

//tcp_client.cpp

#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
	
void usage(string _proc)
{
	cout<<_proc<<"[remote ip][remote port]"<>msg;
		write(sock,msg.c_str(),msg.size());
	}
	return 0;
}

//Makefile

.PHONY:all
all:tcp_server tcp_client

tcp_server:tcp_server.cpp
	g++ -o $@ $^ -lpthread -D_V3_
tcp_client:tcp_client.cpp
	g++ -o $@ $^

.PHONY:clean
clean:
	rm -f tcp_server tcp_client