套接字编程——基于TCP协议

  1. 基础知识

    (1)socket

    a. 什么是socket?

    socket这个词可以表示很多概念,这儿我们讲的socket是:“IP地址+端口号(TCP或UDP端口号)”。在TCP/IP协议中,它唯一标识网络通讯中的一个进程。

    b. socket有什么用?

    在TCP协议中,建立连接的两个进程各自有一个socket来标识,这两个socket组成 的socket pair就唯一标识一个连接。socket本身有“插座”的意思,因此用来描述网络连接的一 对一关系。

    c.什么叫socketAPI

    为TCP/IP协议设计的应用层编程接口称为socketAPI。



2. 程序实现图

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

态,

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



3. 相关函数

(1)创建套接字——socket()

a.  参数

domain:表示底层通信所使用的协议,有很多选项。这儿我们选择AF_INET格式,IPv4网络协议;

type:表示协议实现的方式,也有很多选项。这儿我们用SOCK_STREAM,它 提供有序的、可靠的、双向的和基于连接的字节流,使用带外数据传送机制,为Internet地址族使用TCP。 (在UDP中,我们使用参数SOCK_DGRAM ,它支持无连接的、不可靠的和使用固定大小(通常很小)缓冲区的数据报服务);

protocol:套接口所用的协议。前面两个参数设定后,这儿可用0指定,表示缺省。

b. 返回值

成功返回新创建socket的文件描述符,失败返回-1

(2)绑定端口——bind()

a.   参数

sockfd:表示一个已经建立的socket编号(描述符);

addr:指向sockaddr结构体类型的指针;

addrlen:addr结构的长度,可以用sizeof函数获得。

b. 返回值

成功返回0,失败返回-1。

(3)监听客户请求——listen()

a. 参数

sockfd:表示一个已经建立的socket编号(描述符);

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

b. 返回值

成功返回0,失败返回-1。

(4)接受客户端连接——accept()

返回值: 成功返回接受的socket文件描述符,失败返回-1。

(5)连接服务器——connect()

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



4. 数据传输的过程

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

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



5. 代码实现

//tcp_server.cpp
 1 #include<iostream>
  2 #include<string>
  3 #include<string.h>
  4 #include<stdlib.h>
  5 #include<sys/socket.h>
  6 #include<sys/types.h>
  7 #include<netinet/in.h>
  8 #include<arpa/inet.h>
  9 #include<errno.h>
 10 #include<pthread.h>
 11 
 12 using namespace std;
 13 const int g_backlog=5;
 14 
 15 void usage(string _proc)
 16 {   
 17     cout<<"Usage:"<<_proc<<"[ip][port]"<<endl;
 18 }
 19 static int startup(const string &ip,const int &port)
 20 {
 21     //1.
 22     int sock=socket(AF_INET,SOCK_STREAM,0);
 23     if(sock<0)
 24     {
 25         cerr<<strerror(errno)<<endl;
 26         exit(1);
 27     }
 28     //2.
 29     struct sockaddr_in local;
 30     local.sin_family=AF_INET;
 31     local.sin_port=htons(port);
 32     local.sin_addr.s_addr=inet_addr(ip.c_str());
 33     //3.
 34     if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
 35     {
 36         cerr<<strerror(errno)<<endl;
 37         exit(2);
 38     }
 39     //4.
 40     if(listen(sock,g_backlog)<0)
 41     {
 42         cerr<<strerror(errno)<<endl;
 43         exit(3);
 44     }
 45     return sock;
 46 }
 47 void *thread_run(void *arg)
 48 {
 49     int sock=(int)arg;
 50     char buf[1024];
 51     while(1)
 52     {
 53         memset(buf,‘\0‘,sizeof(buf));
 54         ssize_t _size=read(sock,buf,sizeof(buf)-1);
 55         if(_size>0)
 56         {
 57             //read success
 58             buf[_size]=‘\0‘;
 59         }
 60         else if(_size==0)
 61         {
 62             //client close
 63             cout<<"client close..."<<endl;
 64             break;
 65         }
 66         else
 67         {
 68             cout<<strerror(errno)<<endl;
 69         }
 70         cout<<"client# "<<buf<<endl;
 71         }
 72     //close(sock);
 73     return NULL;
 74 }
 75 
 76 int main(int argc,char* argv[])
 77 {
 78     if(argc!=3)
 79     {
 80         usage(argv[0]);
 81         exit(1);
 82     }
 83     string ip=argv[1];
 84     int port=atoi(argv[2]);
 85     int listen_sock=startup(ip,port);
 86 
 87     struct sockaddr_in client;
 88     socklen_t len = sizeof(client);
 89     while(1)
 90     {
 91         int new_sock=accept(listen_sock,(struct sockaddr*)&client,&len);
 92         if(new_sock<0)
 93         {
 94             cerr<<strerror(errno)<<endl;
 95             continue;
 96         }
 97         cout<<"get a connect..."<<"sock:"<<new_sock 98             <<"ip:"<<inet_ntoa(client.sin_addr)<<"port:" 99             <<ntohs(client.sin_port)<<endl;
100 #ifdef _v1_
101         //version 1
102         char buf[1024];
103         while(1)
104         {
105             ssize_t _size=read(new_sock,buf,sizeof(buf)-1);
106             if(_size>0)
107             {
108                 //read success
109                 buf[_size]=‘\0‘;
110             }
111             else if(_size==0)
112             {
113                 //client close
114             }
115             else
116             {
117                 cout<<strerror(errno)<<endl;
118             }
119             cout<<"client# "<<buf<<endl;
120         }
121 #elif _v2_
122         cout<<"v2"<<endl;
123         pid_t id =fork();
124         if(id==0)
125         {
126             //child
127             std::string _client=inet_ntoa(client.sin_addr);
128             close(listen_sock);
129             char buf[1024];
130             while(1)
131             {
132                 memset(buf,‘\0‘,sizeof(buf));
133                 ssize_t _size=read(new_sock,buf,sizeof(buf)-1);
134                 if(_size>0)
135                 {
136                     //read success
137                     buf[size]=‘\0‘;
138                 }
139                 else if(_size==0)
140                 {
141                     //client close
142                     cout<<_client<<"close..."<<endl;
143                     break;
144                 }
145                 else
146                 {
147                     cout<<strerror(errno)<<endl;
148                 }
149                 cout<<_client<<"# "<<buf<<endl;
150             }
151             close(new_sock);
152             exit(0);
153         }
154         else if(id>0)
155         {
156             close(new_sock);
157         }
158         else
159         {}
160 #elif _v3_
161         pthread_t tid;              
162         pthread_create(&tid,NULL,thread_run,(void*)new_sock);
163         pthread_detach(tid);
164 #else
165     cout<<"default"<<endl;
166 #endif
167 }
168 return 0;
169 }  

//tcp_client.cpp
  1 #include<iostream>
  2 #include<string>
  3 #include<string.h>
  4 #include<unistd.h>
  5 #include<stdlib.h>
  6 #include<sys/socket.h>
  7 #include<sys/types.h>
  8 #include<netinet/in.h>
  9 #include<arpa/inet.h>
 10 #include<errno.h>
 11 
 12 using namespace std;
 13 void usage(string _proc)
 14 {
 15     cout<<_proc<<"[remote ip] [remote port]"<<endl;
 16 }
 17 int main(int argc,char* argv[])
 18 {
 19     if(argc!=3)
 20     {
 21         usage(argv[0]);
 22         exit(1);
 23     }
 24 
 25     int r_port=atoi(argv[2]);
 26     string r_ip=argv[1];
 27 
 28     int sock=socket(AF_INET,SOCK_STREAM,0);
 29     if(sock<-1)
 30     {
 31         cout<<strerror(errno)<<endl;
 32         exit(1);
 33     }
 34 
 35     struct sockaddr_in remote;
 36     remote.sin_family=AF_INET;
 37     remote.sin_port=htons(r_port);
 38     remote.sin_addr.s_addr=inet_addr(r_ip.c_str());
 39 
 40     int ret = connect(sock,(struct sockaddr*)&remote,sizeof(remote));
 41     if(ret<0)
 42     {
 43         cout <<strerror(errno)<<endl;
 44     }
 45     string msg;
 46     while(1)
 47     {
 48         cout<<"please Enter:";
 49         cin>>msg;
 50         write(sock,msg.c_str(),msg.size());
 51     }
 52     return 0;
 53 }
 
 //makefile
  1 .PHONY:all
  2 all:tcp_client tcp_server
  3 tcp_client:tcp_client.cpp
  4     g++ -o [email protected] $^
  5 tcp_server:tcp_server.cpp
  6     g++ -o [email protected] $^ -lpthread -D_v3_
  7 .PHONY:clean
  8 clean:
  9     rm -f tcp_client tcp_server
  
  //statr.sh
  1 #!/bin/bash
  2 
  3 service iptables stop
  4 ./tcp_server 192.168.163.128 8080
时间: 2024-11-09 22:36:11

套接字编程——基于TCP协议的相关文章

基于UDP协议的socket套接字编程 基于socketserver实现并发的socket编程

基于UDP协议 的socket套接字编程 1.UDP套接字简单示例 1.1服务端 import socket server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 建立一个UDP协议的服务器 server.bind(("127.0.0.1",8080)) while True: data,addr = server.recvfrom(1024) server.sendto(data.upper(),addr) server

网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程

Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服务器进程B1同时为客户进程A1.A2和B2提供服务. Socket概述 ①   所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过“套接字”向网络发出请求或者应答网络请求. ②   Socket是连接运行在网络上的两个程序间的双向通信的端点. ③  

Python网络编程—socket套接字编程(TCP)

套接字介绍 1.套接字 : 实现网络编程进行数据传输的一种技术手段 2.Python实现套接字编程:import socket 3.套接字分类 流式套接字(SOCK_STREAM): 以字节流方式传输数据,实现tcp网络传输方案.(面向连接--tcp协议--可靠的--流式套接字) 数据报套接字(SOCK_DGRAM):以数据报形式传输数据,实现udp网络传输方案.(无连接--udp协议--不可靠--数据报套接字) tcp套接字 服务端流程 1.创建套接字 sockfd=socket.socket

套接字中的TCP协议

socket(套接字) 本地回环地址 127.0.0.1 我们先来写一个简单地服务器和客户端 服务端 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import socket ? server = socket.socket()  # 就比如买了一个手机 server.bind(("127.0.0.1",8080))  # bind中绑定的是IP地址和端口号,注意是一个元组,就比如,将手机卡,插入了手机 server.listen(5)  # 半连接池,最大等待

C# socket网络编程 基于TCP协议

socket 服务器端: 1.创建socket Socket tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//三个参数分别为枚举类型(网络),Socket类型,协议 2.绑定ip和端口号 IPAddress ipAddress = new IPAddress(new byte[] {192,168,119,1}); EndPoint point =new IPEnd

TCP下的套接字编程

1.什么是套接字 应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题.多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据.为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口.区分不同应用程序进程间的网络通信和连接,主要有3个参数:通信的目的IP地址.使用的传输层协议(TCP或UDP)和使用的端口号.Socket原意是"插座".通过将这3个参数结合起来,

基于TCP协议的socket套接字编程

基于TCP协议的socket套接字编程 一.什么是Socket Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议. 所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的. [ 注意:也有

《网络编程》基于 TCP 套接字编程的分析

本节围绕着基于 TCP 套接字编程实现的客户端和服务器进行分析,首先给出一个简单的客户端和服务器模式的基于 TCP 套接字的编程实现,然后针对实现过程中所出现的问题逐步解决.有关基于 TCP 套接字的编程过程可参考文章<基本 TCP 套接字编程>.该编程实现的功能如下: (1)客户端从标准输入读取文本,并发送给服务器: (2)服务器从网络输入读取该文本,并回射给客户端: (3)客户端从网络读取由服务器回射的文本,并通过标准输出回显到终端: 简单实现流图如下:注:画图过程通信双方是单独的箭头,只

Learning-Python【28】:基于TCP协议通信的套接字

什么是 Socket Socket 是应用层与 TCP/IP 协议通信的中间软件抽象层,它是一组接口.在设计模式中,Socket 其实就是一个门面模式,它把复杂的 TCP/IP 协议族隐藏在 Socket 接口后面,对用户来说,一组简单的接口就是全部,让 Socket 去组织数据,以符合指定的协议. 所以,我们无需深入理解 TCP/UDP 协议,socket 已经为我们封装好了,我们只需要遵循 socket 的规定去编程,写出的程序自然就是遵循 TCP/UDP 标准的. 套接字的分类: 基于文件