教你如何编写TCP协议的客户端/服务器程序
TCP协议是网络编程中较为常见的协议之一,客户端/服务器程序也是开发中经常需要涉及到的应用场景。在本文中,将会详细介绍如何编写TCP协议的客户端/服务器程序,让读者能够掌握TCP协议的基本原理,以及如何使用C语言实现客户端/服务器程序。
一、TCP协议简介
TCP(Tranission Control Protocol,传输控制协议)是一个可靠的、面向连接的、基于流的传输层通信协议。它是IP协议族中的一员,主要用于互联网中数据的传输。TCP协议通过三次握手建立连接,可以提供完整的数据传输保证,同时也支持流量控制和拥塞控制,使得数据传输更加可靠和高效。
二、客户端/服务器程序设计
客户端/服务器程序是指一种系统架构,该架构中客户端与服务器之间通过网络通信来完成数据交互。在TCP协议中,客户端和服务器之间需要建立连接,才能进行通信。我们可以将服务器端理解为提供服务的主机,而客户端则是请求服务的主机。
在进行客户端/服务器程序设计时,我们需要了解请求方和响应方之间的通信流程。客户端向服务器发起连接请求,服务器收到请求后应做出响应,双方建立连接;之后,客户端向服务器发送请求,服务器接收到请求后进行相关处理,并返回处理结果给客户端。通信结束后,双方需要关闭连接。
三、实现TCP协议的客户端/服务器程序
在C语言中,我们可以使用socket和select函数来实现TCP协议的客户端/服务器程序。
1. 服务器端程序实现
服务器端程序需要完成以下几个步骤:
1)创建socket:使用socket函数创建套接字,该函数返回套接字文件描述符。
int socket(int domn, int type, int protocol);
2)绑定端口:使用bind函数将套接字绑定到一个端口上。
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
3)监听连接请求:使用listen函数监听连接请求。
int listen(int sockfd, int backlog);
4)接收连接请求:使用accept函数接收客户端的连接请求,并返回套接字文件描述符。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
5)数据交互:通过读写套接字实现与客户端之间的数据交互。
示例代码如下:
#include
#include
#include
#include
#include
#include
#include
const int MAXLINE = 4096;
const int PORT = 9999;
const int MAXCONN = 100;
int mn() {
//1. 创建socket
int listenfd, connfd;
struct sockaddr_in servaddr, clientaddr;
char buff[MAXLINE];
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd == -1) {
perror(“socket error”);
exit(1);
}
printf(“socket ok\n”);
//2. 绑定端口
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
perror(“bind error”);
exit(1);
}
printf(“bind ok\n”);
//3. 监听连接请求
if (listen(listenfd, MAXCONN) == -1) {
perror(“listen error”);
exit(1);
}
printf(“listen ok\n”);
//4. 接收连接请求
while (1) {
socklen_t clilen = sizeof(clientaddr);
connfd = accept(listenfd, (struct sockaddr *)&clientaddr, &clilen);
if (connfd == -1) {
perror(“accept error”);
exit(1);
}
printf(“accept ok\n”);
//5. 数据交互
int n;
while ((n = read(connfd, buff, MAXLINE)) > 0) {
buff[n] = ‘\0’;
printf(“recv: %s”, buff);
write(connfd, buff, strlen(buff)+1);
}
//6. 关闭连接
close(connfd);
printf(“close ok\n”);
}
return 0;
}
2. 客户端程序实现
客户端程序需要完成以下几个步骤:
1)创建socket:使用socket函数创建套接字,该函数返回套接字文件描述符。
int socket(int domn, int type, int protocol);
2)连接服务器:使用connect函数连接指定的服务器。
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
3)数据交互:通过读写套接字实现与服务器之间的数据交互。
4)关闭连接:使用close函数关闭连接。
示例代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
const int MAXLINE = 4096;
const int PORT = 9999;
int mn(int argc, char **argv) {
if (argc != 2) {
printf(“usage: ./client \n”);
}
//1. 创建socket
int sockfd;
struct sockaddr_in servaddr;
char buff[MAXLINE];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror(“socket error”);
exit(1);
}
printf(“socket ok\n”);
//2. 连接服务器
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) == -1) {
perror(“inet_pton error”);
exit(1);
}
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
perror(“connect error”);
exit(1);
}
printf(“connect ok\n”);
//3. 数据交互
int n;
while (fgets(buff, MAXLINE, stdin) != NULL) {
if (write(sockfd, buff, strlen(buff)+1) == -1) {
perror(“write error”);
exit(1);
}
if ((n = read(sockfd, buff, MAXLINE)) > 0) {
buff[n] = ‘\0’;
printf(“recv: %s”, buff);
}
}
//4. 关闭连接
close(sockfd);
printf(“close ok\n”);
return 0;
}
四、
相关问题拓展阅读:
- C#中TCP进行同步套接字编程,服务器和客户端的工作流程(需要代码和图)
- c++如何让两个Tcp客户端通过服务器 连接后相互通信?
C#中TCP进行同步套接字编程,服务器和客户端的工作流程(需要代码和图)
s端:建立套接字,晌乱绑定端口,监听,发送及接收;
c端丛早:建立套接字,基于端口连接宴郑档,发送及接收。
代码来了,。。
服务器:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Reflection;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace msgServer
{
public partial class frmServer : Form
{
private Socket socket;
private IPAddress myIP;
private IPEndPoint endPoint;
private int point;
private Socket clientSocket;
private Assembly ass = null;
private System.IO.Stream stream = null;
private System.Media.SoundPlayer pl;
private string txt;
private byte bs = new byte;
public frmServer()
{
InitializeComponent();
ass = Assembly.GetExecutingAssembly();
stream = ass.GetManifestResourceStream(“msgServer.msg.wav”);
pl = new System.Media.SoundPlayer(stream);
}
//字体选择
private void btnFont_Click(object sender, EventArgs e)
{
FontDialog font = new FontDialog();
font.ShowEffects = true;
font.ShowColor = true;
font.MinSize = 12;
font.Font = new Font(“楷体_GB2312”, 18, FontStyle.Bold);
font.Color = Color.Blue;
if (font.ShowDialog() == DialogResult.OK)
{
rtxtSend.Font = font.Font;
rtxtSend.ForeColor = font.Color;
}
}
//开始监听
private void btnStart_Click(object sender, EventArgs e)
{
System.Threading.Thread th1 = new System.Threading.Thread(ToConnect);
th1.Start();
}
//去连接
private void ToConnect()
{
try
{
myIP = IPAddress.Parse(txtIP.Text.Trim());//IP
point = Convert.ToInt32(txtPoint.Text.Trim());//Point
endPoint = new IPEndPoint(myIP, point); //终端
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(endPoint);//绑定
socket.Listen(3); //最多3人同时连接
lblStatus.Text = “服务器已经运行…”;
clientSocket = socket.Accept();//等待接受
//连接上时
if (clientSocket.Connected)
{
lblStatus.Text = “已经建立连接.”;
while (true)
{
try
{
clientSocket.Receive(bs, bs.Length, 0);
pl.Play();
rtxtMsg.AppendText(System.Text.Encoding.Unicode.GetString(bs));
}
catch { lblStatus.Text = “连接已经断开.”; }
}
}
}
catch { txtIP.Focus(); txtIP.SelectAll(); MessageBox.Show(“IP error OR Point error”); }
}
//停止监听
private void btnStop_Click(object sender, EventArgs e)
{
try
{
socket.Close(3);
lblStatus.Text = “监听已经停止.”;
}
catch
{
lblStatus.Text = “目前未建立连接.”;
}
}
private void frmServer_KeyPress(object sender, KeyPressEventArgs e)
{
}
private void frmServer_KeyDown(object sender, KeyEventArgs e)
{
if ((e.Control && e.KeyCode == Keys.Enter) || (e.Alt && e.KeyCode == Keys.S))
{
btnSend.PerformClick();//单击发送
}
}
//发送消息
private void btnSend_Click(object sender, EventArgs e)
{
if (rtxtSend.Text.Trim() == “”)
return;
else if (rtxtSend.Text.Trim().ToLower() == “clear()”)
{
rtxtMsg.Clear();
rtxtSend.Text = “”;
return;
}
else if (Regex.IsMatch(rtxtSend.Text.Trim().ToLower(), @”^++$”))
{
string str = rtxtSend.Text.ToLower();
int size = Convert.ToInt32(str.Substring(str.LastIndexOf(‘(‘) + 1,
str.IndexOf(‘)’) – str.LastIndexOf(‘(‘) – 1));
rtxtMsg.Font = new Font(“宋体”, size,FontStyle.Bold);
return;
}
else if (Regex.IsMatch(rtxtSend.Text.Trim().ToLower(), @”^++$”))
{
string str = rtxtSend.Text.ToLower();
string size = str.Substring(str.LastIndexOf(‘(‘) + 1,str.IndexOf(‘)’) – str.LastIndexOf(‘(‘) – 1);
if (Convert.ToInt32(size) > rtxtMsg.Text.Length)
return;
}
else if (Regex.IsMatch(rtxtSend.Text.Trim().ToLower(), @”^++$”))
{
string str = rtxtSend.Text.ToLower();
string size = str.Substring(str.LastIndexOf(‘(‘) + 1,str.IndexOf(‘)’) – str.LastIndexOf(‘(‘) – 1);
}
else if (rtxtSend.Text.Trim().ToLower() == “exit(0)”)
{
this.Close();
return;
}
try
{
byte bs = new byte;
string user = null;
if (txtUser.Text.Trim() == “在此输入你的名字” || txtUser.Text.Trim() == “”)
{
user = “我”;
bs = Encoding.Unicode.GetBytes(string.Format(“对方说:({0})\r\n{1}\r\n”,DateTime.Now.ToString(), rtxtSend.Text.Trim()));
}
else
{
bs = Encoding.Unicode.GetBytes(string.Format(“{0}说:({1})\r\n{2}\r\n”, txtUser.Text.Trim(),DateTime.Now.ToString(), rtxtSend.Text.Trim()));
user = txtUser.Text.Trim();
}
clientSocket.Send(bs, bs.Length, 0);//发送
txt = string.Format(“{0}说:({1})\r\n{2}\r\n”, user, DateTime.Now.ToString(),rtxtSend.Text.Trim());
int tempLen = rtxtMsg.Text.Length;
rtxtMsg.AppendText(txt);
rtxtMsg.Select(tempLen, txt.Length);
rtxtMsg.SelectionFont = new Font(“宋体”, 10);
rtxtMsg.SelectionColor = Color.Red;
rtxtSend.Clear();
}
catch { MessageBox.Show(“未建立连接,无法发送数据!”); }
}
//关闭Socket
private void frmServer_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
//关闭连接
socket.Close(3);
}
catch (Exception) { }
finally
{
foreach (Process p in Process.GetProcesses())
{
if (p.ProcessName == Application.ProductName)
p.Kill();
}
}
}
private void frmServer_Load(object sender, EventArgs e)
{
foreach (Process p in Process.GetProcesses())
{
if (p.ProcessName == Application.ProductName)//已经启动
{
if (p.Id != Process.GetCurrentProcess().Id)//不是当前进程
{
p.Kill();
}
}
}
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
this.TopMost = checkBox1.Checked;
}
}
}
客户端:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace gClient
{
public partial class frmClient : Form
{
private IPAddress IP;//ip
private EndPoint endpoint;//point
private Socket socket;//socket
private System.IO.Stream stream = null;
private System.Reflection.Assembly ass = null;
private System.Media.SoundPlayer pl = null;
private string txt;
private byte bs = new byte;
public frmClient()
{
InitializeComponent();
ass = System.Reflection.Assembly.GetExecutingAssembly();
stream = ass.GetManifestResourceStream(“gClient.msg.wav”);
pl = new System.Media.SoundPlayer(stream);
}
//请求连接
private void btnRequestConnect_Click(object sender, EventArgs e)
{
System.Threading.Thread th = new System.Threading.Thread(this.ToConnect);
th.Start();
}
//连接服务器
private void ToConnect()
{
try
{
IP = IPAddress.Parse(txtIP.Text.Trim());
int point = Convert.ToInt32(txtPoint.Text.Trim());
endpoint = new IPEndPoint(IP, point);
//建立Socket
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//建立连接
socket.Connect(endpoint);
//连接成功
lblStatus.Text = “连接成功.”;
while (true)
{
socket.Receive(bs, bs.Length, 0);
pl.Play();
rtxtMsg.AppendText(System.Text.Encoding.Unicode.GetString(bs));
}
}
catch (FormatException)
{ MessageBox.Show(“IP error OR Point error”); }
catch (ArgumentNullException)
{ MessageBox.Show(“IP error OR Point error”); }
catch (Exception)
{
lblStatus.Text = “连接失败,原因: 服务器已停止.”;
}
}
//字体
private void btnFont_Click(object sender, EventArgs e)
{
FontDialog font = new FontDialog();
font.ShowEffects = true;
font.ShowColor = true;
font.MinSize = 12;
font.Font = new Font(“楷体_GB2312”, 18, FontStyle.Bold);
font.Color = Color.Blue;
if (font.ShowDialog() == DialogResult.OK)
{
rtxtSend.Font = font.Font;
rtxtSend.ForeColor = font.Color;
}
}
//关闭连接
private void btnCloseConnect_Click(object sender, EventArgs e)
{
try
{
socket.Close();
lblStatus.Text = “连接已经关闭.”;
}
catch
{
lblStatus.Text = “目前未建立连接.”;
}
}
//发送消息
private void btnSend_Click(object sender, EventArgs e)
{
if (rtxtSend.Text.Trim() == “”)
return;
else if (rtxtSend.Text.Trim().ToLower() == “clear()”)
{
rtxtMsg.Clear();
rtxtSend.Text = “”;
return;
}
else if (Regex.IsMatch(rtxtSend.Text.Trim().ToLower(), @”^++$”))
{
string str = rtxtSend.Text.ToLower();
int size = Convert.ToInt32(str.Substring(str.LastIndexOf(‘(‘) + 1,
str.IndexOf(‘)’) – str.LastIndexOf(‘(‘) – 1));
rtxtMsg.Font = new Font(“宋体”, size, FontStyle.Bold);
return;
}
else if (Regex.IsMatch(rtxtSend.Text.Trim().ToLower(), @”^++$”))
{
string str = rtxtSend.Text.ToLower();
string size = str.Substring(str.LastIndexOf(‘(‘) + 1, str.IndexOf(‘)’) – str.LastIndexOf(‘(‘) – 1);
if (Convert.ToInt32(size) > rtxtMsg.Text.Length)
return;
}
else if (Regex.IsMatch(rtxtSend.Text.Trim().ToLower(), @”^++$”))
{
string str = rtxtSend.Text.ToLower();
string size = str.Substring(str.LastIndexOf(‘(‘) + 1, str.IndexOf(‘)’) – str.LastIndexOf(‘(‘) – 1);
}
else if (rtxtSend.Text.Trim().ToLower() == “exit(0)”)
{
this.Close();
return;
}
try
{
byte bs = new byte;
string user = null;
if (txtUser.Text.Trim() == “在此输入你的名字” || txtUser.Text.Trim() == “”)
{
user = “我”;
bs = Encoding.Unicode.GetBytes(string.Format(“对方说:({0})\r\n{1}\r\n”, DateTime.Now.ToString(),rtxtSend.Text.Trim()));
}
else
{
bs = Encoding.Unicode.GetBytes(string.Format(“{0}说:({1})\r\n{2}\r\n”, txtUser.Text.Trim(),DateTime.Now.ToString(),rtxtSend.Text.Trim()));
user = txtUser.Text.Trim();
}
socket.Send(bs, bs.Length, 0);//发送
txt = string.Format(“{0}说:({1})\r\n{2}\r\n”, user, DateTime.Now.ToString(), rtxtSend.Text.Trim());
int tempLen = rtxtMsg.Text.Length;
rtxtMsg.AppendText(txt);
rtxtMsg.Select(tempLen, txt.Length);
rtxtMsg.SelectionFont = new Font(“宋体”, 10);
rtxtMsg.SelectionColor = Color.Red;
rtxtSend.Clear();
}
catch(Exception ex)
{ MessageBox.Show(“连接尚未建立!无法发送数据!” + ex.Message); }
}
//避开打开多个
private void frmClient_Load(object sender, EventArgs e)
{
foreach (Process p in Process.GetProcesses())
{
if (p.ProcessName == Application.ProductName)//有进程
{
if (p.Id != Process.GetCurrentProcess().Id)//不是当前进程
{
p.Kill();
}
}
}
}
private void frmClient_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
socket.Close();
}
catch(Exception) { }
finally
{
foreach (Process p in Process.GetProcesses())
{
if (p.ProcessName == Application.ProductName)
p.Kill();
}
}
}
private void frmClient_KeyDown(object sender, KeyEventArgs e)
{
if ((e.Control && e.KeyCode == Keys.Enter) || (e.Alt && e.KeyCode == Keys.S))
{
btnSend.PerformClick();
}
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
this.TopMost = checkBox1.Checked;
}
}
c++如何让两个Tcp客户端通过服务器 连接后相互通信?
你这相当于一个软件工裂袜稿程项目,QQ、微信、钉钉都是这种模式,自己好野要开发,即使功能没那么复肆孝杂,也需要开发服务端和客户端两套程序,你可以在网上找找有没有现成的。
tcp 服务器客户端程序的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于tcp 服务器客户端程序,教你如何编写TCP协议的客户端/服务器程序。,C#中TCP进行同步套接字编程,服务器和客户端的工作流程(需要代码和图),c++如何让两个Tcp客户端通过服务器 连接后相互通信?的信息别忘了在本站进行查找喔。