实验平台

linux

实验内容

编写TCP服务器和客户端程序,程序运行时服务器等待客户端连接。一旦连接成功,服务器显示客户端的IP地址和端口号,并向客户端发送字符串

实验原理

TCP是面向连接的通信,其主要实现过程如下:

我们将服务器代码分为两部分。

1. init_tcp_server() tcp服务器的初始化

2. main() 实现读写数据

这样做的好处是main函数不必写的特别冗长,利于维护。从框架上来说,服务器的初始化也与读、写无关。

tcp服务器的初始化----init_tcp_server()

1. 创建socket

sockfd = socket(AF_INET, SOCK_STREAM, ); //AF_INT:ipv4, SOCK_STREAM:tcp协议

2. 设置socket  当然这一步可以省略

int32_t opt = ;
ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

详细说明:

3. 绑定(bind函数)

将socket和地址(包括ip,port)绑定。需要定义一个结构体地址,以便于将port的主机字节序转化成网络字节序

struct sockaddr_in serveraddr;    //地址结构体

bind函数

bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))

4. listen监听,将接收到的客户端放入队列

 listen(sockfd,)  //第二个参数是队列长度

5. 调用accept函数,从队列获取请求,返回socket描述符,如果没有请求(没有客户端连接),将会阻塞,直到获取请求

int fd=accept(sockfd, (struct sockaddr*)&clientaddr, &clientaddr_len);

至此服务器初始化完成,返回成功连接的套接字fd。

服务器端代码如下:tcpserver.c

#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h> #define PORT 1234
#define BACKLOG 10
#define BUFFER_SIZE 100 /**
* @brief 初始化tcp服务器
* @param[in] listenfd 监听套接字
* @return -1 - 失败, socket 文件句柄 - 成功
*/
int32_t init_tcp_server(int32_t listenfd)
{
struct sockaddr_in server;
struct sockaddr_in client; int32_t connectfd = ;
int32_t addrlen;
int32_t ret = ;
addrlen = sizeof(client); /**< 创建一个tcp套接字 */
listenfd = socket(AF_INET, SOCK_STREAM, );
if (listenfd == -)
{
perror("create socket failed!\n");
exit();
} /**< 设置一个tcp套接字 */
int32_t opt = ;
ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (ret < )
{
perror("set socket failed!\n");
exit();
} /**< 设置服务器监听所有的IP地址 */
bzero(&server, sizeof(struct sockaddr_in));
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)) == -)
{
perror("bind error");
exit();
} /**< 监听 */
if (listen(listenfd, BACKLOG) == -)
{
perror("listen error");
exit();
} /**< 等待客户端连接,如果没有,一直阻塞 */
if ((connectfd = accept(listenfd, (struct sockaddr *)&client, &addrlen)) == -)
{
perror("accept error");
close(listenfd);
close(connectfd);
exit();
}
printf("You got a connection from client's ip is %s, port is %d\n", inet_ntoa(client.sin_addr), htons(client.sin_port)); return connectfd;
} int main()
{
int32_t listenfd = ;
int32_t connectfd = ;
char buf[BUFFER_SIZE] = "Welcome to my server"; connectfd = init_tcp_server(listenfd); send(connectfd, buf, BUFFER_SIZE, ); /**< 发送信息到客户端 */
close(connectfd);
close(listenfd);
}

客户端

同样,将客户端代码分成两部分:

1. init_tcp_client() tcp客户端的初始化

2. main() 实现读写数据

客户端的初始化较为简单,如上图,只要实现socket和connect函数即可。但是我们希望可以手动输入客户端连接的IP地址,便于以后扩展,因此需要给客户端初始化传入一个参数。例如,输入:

./tcpclient 127.0.0.1

客户端代码如下:tcpclient.c

#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h> #define PORT 1234
#define BUFFER_SIZE 100 int32_t init_tcp_client(char *ipaddr)
{
int sockfd = ;
struct sockaddr_in server; if ((sockfd = socket(AF_INET, SOCK_STREAM, )) == -)
{
perror("create socket failed!\n");
exit();
} bzero(&server, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
inet_pton(AF_INET, ipaddr, &server.sin_addr.s_addr); /**< 点分十进制转换成二进制的网络字节序 */ if (connect(sockfd, (struct sockaddr *)&server, sizeof(server)) == -)
{
perror("connect error");
exit();
} return sockfd;
} int32_t main(int argc, char*argv[])
{
int32_t sockfd, num;
char buf[BUFFER_SIZE];
if (argc != )
{
printf("Usage:%s <IP Address>\n",argv[]);
exit();
}
sockfd = init_tcp_client(argv[]); if ((num = recv(sockfd, buf, BUFFER_SIZE, )) == -)
{
perror("recv error");
exit();
} buf[num - ] = '\0';
printf("Server Message: %s\n", buf);
close(sockfd); return ;
}

Makefile文件如下:

all:server client

server:tcpserver.c
gcc tcpserver.c -o server client:tcpclient.c
gcc tcpclient.c -o client clean:
rm -rf server client

实验结果如下:

基于TCP的客户端和服务器端的代码设计的更多相关文章

  1. 基于UDP的客户端和服务器端的代码设计

    实验平台 linux 实验内容 编写UDP服务器和客户端程序,客户端发送消息,服务器接收消息,并打印客户端的IP地址和端口号. 实验原理 UDP是无需连接的通信,其主要实现过程如下: 同样,我们可以按 ...

  2. 基于TCP的客户端、服务器端socket编程

    一.实验目的 理解tcp传输客户端服务器端通信流程 二.实验平台 MAC OS 三.实验内容 编写TCP服务器套接字程序,程序运行时服务器等待客户的连接,一旦连接成功,则显示客户的IP地址.端口号,并 ...

  3. UDP广播的客户端和服务器端的代码设计

    实验环境 linux 注意: 使用UDP广播,是客户端发送广播消息,服务器端接收消息.实际上是客户端探测局域网中可用服务器的一种手段.客户端发送,服务器端接收,千万不能弄混淆!!! 为了避免混淆,本文 ...

  4. 使用CXF开发WebService程序的总结(四):基于bean的客户端和服务端代码的编写

    1. 在原服务端项目 ws_server中添加两个bean 1.1 添加两个类  User 和 Clazz   package com.lonely.pojo; public class User { ...

  5. 实验09——java基于TCP实现客户端与服务端通信

    TCP通信         需要先创建连接 - 并且在创建连接的过程中 需要经过三次握手        底层通过 流 发送数据 数据没有大小限制        可靠的传输机制 - 丢包重发 包的顺序的 ...

  6. C/S模型:TCP,UDP构建客户端和服务器端(BIO实现

    Java中提供了socket编程来构建客户端和服务器端 TCP构建服务器端的步骤:(1)bind:绑定端口号(2)listen:监听客户端的连接请求(3)accept:返回和客户端连接的实例(4)re ...

  7. 【TCP/IP网络编程】:04基于TCP的服务器端/客户端

    摘要:结合前面所讲述的知识,本篇文章主要介绍了简单服务器端和客户端实现的框架流程及相关函数接口. 理解TCP和UDP 根据数据传输方式的不同,基于网络协议的套接字一般分为TCP套接字和UDP套接字(本 ...

  8. C/C++网络编程5——实现基于TCP的服务器端/客户端2

    三次握手过程详解: 1:客户端的协议栈向服务器端发送SYN包,并告诉服务器端当前放送序号为j,客户端进入SYNC_SEND状态. 2:服务器端的协议栈收到这个包以后,和客户端进行ACK应答,应答值为j ...

  9. 基于TCP的安卓客户端开发

    一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户 ...

随机推荐

  1. Flask 入门(九)

    外键数据库 我们想想,所有的数据不可能这么简单,万一建的数据库有了外键呢?如何增加,如何查询? 承接上文: 先登录mysql数据库,把里面的表和数据都删了 执行语句: use data select ...

  2. redis 非关系型数据库

    redis 类型,数据存在磁盘里面,所以存储速度比较快,其他数据类型还是存储在数据库所以比较慢些 链接redis数据库: r=redis.Redis(host="%%%%%%%", ...

  3. ThinkPHP中的行为扩展和插件详解

    原理分析 将标签与类之间的对应关系(如'app_init'=>array('Common\Behavior\InitHook')),通过Hook类中import或add方法,加载到Hook类中静 ...

  4. 《深入理解 Java 虚拟机》读书笔记:垃圾收集器与内存分配策略

    正文 垃圾收集器关注的是 Java 堆和方法区,因为这部分内存的分配和回收是动态的.只有在程序处于运行期间时才能知道会创建哪些对象,也才能知道需要多少内存. 虚拟机栈和本地方法栈则不需要过多考虑回收的 ...

  5. Loading纯JS

    function showLoading() { document.getElementById("over").style.display = "block" ...

  6. FJUT2019暑假第二次周赛题解

    A 服务器维护 题目大意: 给出时间段[S,E],这段时间需要人维护服务器,给出n个小时间段[ai,bi],代表每个人会维护的时间段,每个人维护这段时间有一个花费,现在问题就是维护服务器[S,E]这段 ...

  7. 微服务统计,分析,图表,监控, 分布式追踪一体化的 HttpReports 在 .Net Core 的应用

    前言介绍 HttpReports 是针对.Net Core 开发的轻量级APM系统,基于MIT开源协议, 使用HttpReports可以快速搭建.Net Core环境下统计,分析,图表,监控,分布式追 ...

  8. kafka消息分区机制原理

    背景 kafka如何支撑海量消息的集中写入? 答案就是消息分区. 核心思想是:负载均衡,采用合适的分区策略把消息写到不同的broker上的分区中: 其它的产品中有类似的思想. 比如monogodb, ...

  9. 基于netty实现rpc框架-spring boot客户端

    上篇讲了RPC服务端的实现.原理就是解析netty通道数据拿到类.方法及入参等信息,然后通过java反射机制调用本地接口返回结果.没有用到很复杂的技术. 这篇我们将客户端的实现.说白了客户端的任务很简 ...

  10. linq详细案例

    LINQ to SQL语句(1)之Where 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子句.Where操 ...