TCP 服务器客户端程序设计
来源:互联网 发布:软件硬件英语 编辑:程序博客网 时间:2024/05/22 18:09
一、socket 简介
1、socket 是网络编程的一种接口,它是一种接口,它是一种特殊的I/O,用socket函数建立一个socket 连接,此函数返回一个整形的socket描述符,随后进行数据传输。
-----------------------------------------------------------------
#include <sys/socket.h>
int socket(int family,int type,int protocol);
返回:非负描述字---成功 -1---失败
-----------------------------------------------------------------
第一个参数指明了协议簇,目前支持5种协议簇,最常用的有AF_INET(IPv4协议)和AF_INET6(IPv6协议);第二个参数指明套接口类型,有三种类型可选:SOCK_STREAM(字节流套接口)、SOCK_DGRAM(数据报套接口)和SOCK_RAW(原始套接口);如果套接口类型不是原始套接口,那么第三个参数就为0。
通常socket分为三种类型:流式socket 数据报socket 原始socket
注意:一个完整的socket有一个本地唯一的socket号,由操作系统分配。最重要的是面向客户/服务器模型而设计的。
2、一个IP地址,一个通讯端口,就能确定一个通讯程序的位置,为此开发人员专门设计了一个套接结构,就是把网络程序中所用到的网络地址和端口信息放在一个结构体中。
一般套接口地址结构都以“socketaddr"开头。socket 根据所使用的协议的不同可分为TCP套接口和UDP套接口,又称为流式套接口和数据套接口。
UDP是一个无连接协议,TCP是个可靠的端对端协议。传输UDP数据包时,LINUX不知道也不关心它们是否已经安全到达目的地,而传输TCP数据包时,则应先建立连接以保证传输的数据被正确接收。
3、两个重要的数据类型:sockadd和sockaddr_in,这两个结构类型都是用来保存socket信息的,如IP地址、通信端口等。
3、TCP编程
这里与 电话通信进行对比
下面是各个函数的功能
b
bind 函数
完成此步,该socket拥有了本地IP地址,端口,通信协议,不能接收客户端的请求,但可以向服务器发起连接。
connect函数
其第一个参数为socket返回的文件描述符。
第二个参数储存了服务器端的地址(包括服务器的IP地址和端口信息)。
第三个参数为该地址的长度。
如果执行成功,此函数将与地址为addr的服务器建立连接,并返回0,如果失败则返回-1。
正确完成此步:客户端socket拥有了目的IP,端口信息。
Listen函数
第一个参数是绑定了IP及端口信息的socket文件描述符。
第二个参数为请求排队的最大长度。当有多个客户端程序和服务器端相连时, 此值表示可以使用的处于等待的队列长度。
listen 函数将绑定的socket文件描述符变为监听套接字,完成此步: 服务器已经准备接收客户端连接请求了。
accept 函数
第一个参数是监听网络后的socket文件描述符。
第二参数为struct sockaddr 类型的地址空间首地址,第三个参数为该段地址空间长度,因此第二个参数用来存储客户端的IP地址和端口信息,以便为客户端返回数据。
需要注意的是,如果执行成功,此函数将返回一个新的文件描述符以标识该连接,从而使原来的文件描述符可以继续等待新的连接,这样便可以实现多客户端。如果执行失败,将返回-1。
sends recv 函数
第一个参数为发送的目标socket对象;
第二个参数为欲发送的数据位置;
第三个参数为数据的大小;
第四个参数操作flags,支持的值为0或MSG_OOB(发送带外数据)等。对套接字调用write()的行为与将flags设置为0的send()的行为完全相同。
如果执行成功,此函数将返回发送数据的大小,如果失败,将返回-1
具体执行过程如下:
首先,服务器端需要做以下准备工作:
(1)调用socket()函数。建立socket对象,指定通信协议。
(2)调用bind()函数。将创建的socket对象与当前主机的某一个IP地和端口绑定。
(3)调用listen()函数。使socket对象处于监听状态,并设置监听队列大小。
客户端需要做以下准备工作:
(1)调用socket()函数。建立socket()对象,指定相同通信协议。
(2)应用程序可以显式的调用bind()函数为其绑定IP地址和端口,当然,也可以将这工作交给TCP/IP协议栈。
接着建立通信连接:
(1)客户端调用connect()函数。向服务器端发出连接请求。
(2)服务端监听到该请求,调用accept()函数接受请求,从而建立连接,并返回一个新的socket文件描述符专门处理该连接。
然后通信双方发送/接收数据:
(1)服务器端调用write()或send()函数发送数据,客户端调用read()或者recv()函数接收数据。反之客户端发送数据,服务器端接收数据。
(2)通信完成后,通信双方都需要调用close()或者shutdown()函数关闭socket对象
以下程序在 Fedora 操作系统上运行成功,首先打开终端,输入命令 vim tcpserver.c ,然后将代码输入,退出
执行命令gcc –o tcpserver tcpserver.c生成可执行文件tcpserver
执行命令./ tcpserver
再开一个“终端”,
输入命令 vim tcpclient.c ,然后将代码输入,退出
gcc–o tcpclient tcpclient.c生成可执行文件tcpclient。
执行命令./ tcpclient 127.0.0.1。观察两个“终端”出现的结果。
Server 程序:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 1234 #define BACKLOG 1 int main() { int listenfd, connectfd; struct sockaddr_in server; struct sockaddr_in client; socklen_t addrlen; if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("Creating socket failed."); exit(1); } int opt =SO_REUSEADDR; setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); bzero(&server,sizeof(server)); server.sin_family=AF_INET; server.sin_port=htons(PORT); server.sin_addr.s_addr= htonl (INADDR_ANY); if(bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1) { perror("Binderror."); exit(1); } if(listen(listenfd,BACKLOG)== -1){ /* calls listen() */ perror("listen()error\n"); exit(1); } addrlen =sizeof(client); if((connectfd = accept(listenfd,(struct sockaddr*)&client,&addrlen))==-1) { perror("accept()error\n"); exit(1); } printf("Yougot a connection from cient's ip is %s, prot is %d\n",inet_ntoa(client.sin_addr),htons(client.sin_port)); send(connectfd,"Welcometo my server.\n",22,0); close(connectfd); close(listenfd);return 0; }
client 程序
#include<stdio.h> #include <stdlib.h> #include<unistd.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<netdb.h> #define PORT 1234 #define MAXDATASIZE 100 int main(int argc, char *argv[]) { int sockfd, num; char buf[MAXDATASIZE]; struct hostent *he; struct sockaddr_in server; if (argc!=2) { printf("Usage:%s <IP Address>\n",argv[0]); exit(1); } if((he=gethostbyname(argv[1]))==NULL){ printf("gethostbyname()error\n"); exit(1); } if((sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1){ printf("socket()error\n"); exit(1); } bzero(&server,sizeof(server)); server.sin_family= AF_INET; server.sin_port = htons(PORT); server.sin_addr =*((struct in_addr *)he->h_addr); if(connect(sockfd,(struct sockaddr *)&server,sizeof(server))==-1){ printf("connect()error\n"); exit(1); } if((num=recv(sockfd,buf,MAXDATASIZE,0)) == -1){ printf("recv() error\n"); exit(1); } buf[num-1]='\0'; printf("Server Message: %s\n",buf); close(sockfd);return 0;}0 0
- TCP 服务器客户端程序设计
- Winsock程序设计入门(3)修订版-多线程TCP服务器和客户端
- TCP服务器端和客户端程序设计
- TCP服务器端和客户端程序设计
- TCP服务器端和客户端程序设计
- TCP服务器端和客户端程序设计
- TCP服务器端和客户端程序设计
- TCP服务器端和客户端程序设计
- TCP服务器端和客户端程序设计
- TCP服务器端和客户端程序设计
- TCP服务器/客户端
- TCP服务器/客户端程序
- 5.10TCP客户端服务器
- TCP 服务器与客户端
- TCP客户端服务器
- tcp服务器与客户端
- Python TCP服务器、客户端程序
- TCP客户端与服务器MFC
- 刚刚开始学AT89S52单片机遇到的一些小问题 + 个人解决办法
- adb报错:The connection to adb is down, and a severe&nbs
- 快速幂取模
- mysql启动报错:The server quit without updating PID file (/var/lib/mysql/
- c++-函数重载
- TCP 服务器客户端程序设计
- 用位运算快速求解全部组合数
- 心脏流血(heartbleed)测试结果比对--淘宝(taobao)VS亚马逊(amazon)VS谷歌(google)
- 如何查看通过tar压缩包中的内容
- html5 canvas java 上传
- avsubtitleWriter demo解析(四):writeSubtitles下篇
- Windows 7 Telnet命令实现
- Eclipse中JSP和JavaScript进行Copy卡死,问题解决
- 第七周 项目6--人数不定的工资类