实验平台

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. 2017蓝桥杯取位数(C++B组)

    题目: 标题:取数位求1个整数的第k位数字有很多种方法.以下的方法就是一种.// 求x用10进制表示时的数位长度 int len(int x){ if(x<10) return 1; retur ...

  2. Python高级特性-迭代器和生成器

    迭代器 Python中可迭代对象(iterable)通俗指可直接作用与For循环的数据对象,如Python中的集合数据类型,字符串(str),列表(list),元组(tuple),集合(set),字典 ...

  3. JAVA debug 调试demo

    1.设置断点,在代码的行号后面鼠标左键即可2.想要看调用方法的执行流程,那么调用方法也要加断点. package day6_debug; /* * 1.设置断点,在代码的行号后面鼠标左键即可 * 2. ...

  4. Redis cluster集群配置教程

    这里建议大家安装4.0.9版本的 1.打开Centos虚拟机,登陆. 2.通过WinSCP把Redis集群tar包上传到虚拟机里的目录里,我的目录是 /usr/local 这里我已经上传过了并解压了, ...

  5. 2019-05-25 Python之Mongodb的使用

    Mongodb学习总结: one.插入数据pass two.查看数据pass three.修改数据pass four.数据排序pass five.删除数据pass 一.安装Mongodb https: ...

  6. [算法总结]DFS(深度优先搜索)

    目录 一.关于DFS 1. 什么是DFS 2. DFS的搜索方式 二.DFS的具体实现 三.剪枝 1. 顺序性剪枝 2. 重复性剪枝 3. 可行性剪枝 4. 最优性剪枝 5. 记忆化剪枝 四.练习 一 ...

  7. linux知识点系列之 umask

    介绍 umask(user's mask)用来设置文件权限掩码.权限掩码是由3个八进制的数字所组成,将现有的存取权限减掉权限掩码后,即可产生建立文件时预设的权限. UNIX最初实现时不包含umask命 ...

  8. Mac os Pycharm 中使用Stanza进行实体识别(自然语言处理nlp)

    stanza 是斯坦福开源Python版nlp库,对自然语言处理有好大的提升,具体好在哪里,官网里面都有介绍,这里就不翻译了.下面放上对应的官网和仓库地址. stanza 官网地址:点击我进入 sta ...

  9. pytorch 中的LSTM模块

  10. TensorFlow的图像NCHW与NHWC

    import tensorflow as tf x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] with tf.Session() as sess: a = t ...