• 协议之间的关系

  • socket在哪

  • socket是什么

 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

  门面模式,用自己的话说,就是系统对外界提供单一的接口,外部不需要了解内部的实现。

  • socket编程的基本流程

tcp通信实现多线程连接与群聊

服务器端

  • 定义端口以及本地ip地址

     #define port 9876
    #define ip_addr "192.168.1.102"
  • 创建事件以及互斥量

     HANDLE event;//事件
    HANDLE mutex = NULL;
     event = CreateEvent(NULL, TRUE, FALSE, NULL);//第二个参数TRUE表示手动复位
    mutex = CreateMutex(NULL, FALSE, NULL);//互相排斥
  • 接收连接

     //接受连接
    void recv_connect(void *p)
    {
    WSADATA WSA;//对比版本 SOCKET client,sever;//客户端 //本地地址信息,以及连接的客户端地址信息
    struct sockaddr_in localeaddr,clientaddr;
    int addrlength = ;
    HANDLE hthread1 = NULL;//线程句柄
    HANDLE hthread2 = NULL;
    HANDLE hthread3 = NULL;
    int Ret = ;
    char senbuf[] = { }; //对比版本
    if (WSAStartup(MAKEWORD(, ), &WSA) != )
    {
    puts("版本不一致,通信失败");
    system("pause");
    return;
    }
    //创建通信
    sever = socket(AF_INET, SOCK_STREAM, );
    if (sever == INVALID_SOCKET)
    {
    puts("服务器创建失败");
    system("pause");
    return;
    }
    //设置服务器结构体信息
    localeaddr.sin_family = AF_INET;
    localeaddr.sin_addr.s_addr = inet_addr(ip_addr);
    localeaddr.sin_port = htons(port);
    memset(localeaddr.sin_zero, 0x00, );//清零
    //与socket绑定
    Ret = bind(sever, (struct sockaddr*)&localeaddr, sizeof(localeaddr));
    if (Ret != )
    {
    puts("绑定失败");
    system("pause");
    return;
    }
    Ret = listen(sever, );
    if (Ret != )
    {
    puts("监听失败");
    system("pause");
    return;
    }
    puts("服务器启动"); while ()
    {
    addrlength = sizeof(clientaddr);//获取长度
    //接受客户端连接,信息存放在clientaddr中
    client = accept(sever, (struct sockaddr*) &clientaddr, &addrlength);
    if (client == INVALID_SOCKET)
    {
    puts("接收失败");
    system("pause");
    return;
    }
    printf("\n客户端连接%s 端口号:%d\n", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port);
    //创建写的线程
    hthread3 = CreateThread(NULL, , clientthreadwrite, (void*)client, , NULL);
    } //关闭socket
    closesocket(sever);
    closesocket(client);
    WSACleanup();
    }
  • 向客户端发送消息的多线程函数

     //创建线程向客户端发送消息
    DWORD WINAPI clientthreadwrite(void *p)
    {
    SOCKET client = (SOCKET)p;//数指针类型转换
    int Ret = ; while ()
    {
    WaitForSingleObject(event, INFINITE);//等待事件
    WaitForSingleObject(mutex, INFINITE); if (strlen(sendbuf) != )
    {
    //发送信息
    Ret = send(client, sendbuf, strlen(sendbuf), 0);
    }
    ReleaseMutex(mutex);
    ResetEvent(event);//手动复位
    }
    }
  • 从客户端接收消息的多线程函数

     DWORD WINAPI clientthreadread(void *p)
    {
    //数指针类型转换
    SOCKET client = (SOCKET)p;
    int Ret = ;
    char receivebuf[]; while ()
    {
    //清零
    memset(receivebuf, , );
    //读取
    Ret = recv(client, receivebuf, 256, 0);
    if (Ret == SOCKET_ERROR)
    {
    puts("客户端send失败");
    break;
    }
    printf("\n收到%s,", receivebuf);
    //进入临界区
    WaitForSingleObject(mutex, INFINITE);
    memset(sendbuf, , );
    //全局变量,锁定
    strcpy(sendbuf, receivebuf);
    ReleaseMutex(mutex);
    //通知
    SetEvent(event);
    }
    return ;
    }

      

  • main函数
     void main()
    {
    event = CreateEvent(NULL, TRUE, FALSE, NULL);//第二个参数TRUE表示手动复位
    mutex = CreateMutex(NULL, FALSE, NULL);//互相排斥 _beginthread(recv_connect, , NULL); Sleep();
    while ()
    {
    printf("请输入要发送的信息:");
    scanf("%s", sendbuf);
    SetEvent(event);
    }
    system("pause");
    }

客户端

 #define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include <winsock.h>
#pragma comment(lib,"ws2_32.lib") //定义端口号
#define port 9876
//要连接的ip地址
#define ip_addr "192.168.1.102" void main()
{
//对比版本
WSADATA WSA;
//客户端套接字
SOCKET client;
//服务器信息
struct sockaddr_in severaddr;
//线程句柄
HANDLE hthread = NULL;
//保存连接信息
int Ret = ;
char senbuf[] = { }; if (WSAStartup(MAKEWORD(,),&WSA)!=)
{
puts("版本不一致,通信失败");
system("pause");
return;
}
//创建socket
client = socket(AF_INET, SOCK_STREAM, );
if (client == INVALID_SOCKET)
{
puts("客户端创建失败");
system("pause"); }
//设置服务器信息
severaddr.sin_family = AF_INET;
//设置地址
severaddr.sin_addr.s_addr = inet_addr(ip_addr);
//端口
severaddr.sin_port = htons(port);
//清空
memset(severaddr.sin_zero, 0x00, ); //连接
Ret = connect(client, (struct sockaddr*) &severaddr, sizeof(severaddr));
if (Ret!=)
{
puts("客户端链接失败");
system("pause");
}
while ()
{
//printf("请输入向服务器发送的消息:");
//scanf("%s", senbuf);//输入
//Ret = send(client, senbuf, strlen(senbuf), 0);//发送
//if (Ret==SOCKET_ERROR)
//{
// puts("客户端send失败");
// system("pause");
//}
char receivebuf[];
memset(receivebuf, , );//清零
Ret = recv(client, receivebuf, , );
printf("收到客户端发送的消息:%s\n", receivebuf);
} closesocket(client);
WSACleanup();
}

102.tcp实现多线程连接与群聊的更多相关文章

  1. 104.tcp多线程读写实现群聊

    客户端: #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include <w ...

  2. C/S模型之TCP群聊

    说明:利用TCP协议和多线程实现群聊功能.一个服务器,多个客户端(同一个程序多次启动).客户端向服务端发送数据,由服务端进行转发到其他客户端. /服务端 // WSASever.cpp : 定义控制台 ...

  3. Strophe.js连接XMPP服务器Openfire、Tigase实现Web私聊、群聊(MUC)

    XMPP(Extensible Messaging and Presence Protocol)是一种网络即时通讯协议,它基于XML,具有很强的扩展性,被广泛使用在即时通讯软件.网络游戏聊天.Web聊 ...

  4. Java-->实现群聊功能(C/S模式--TCP协议)

    --> Java 对TCP协议的支持: --> java.net包中定义了两个类ServerSocket 和Socket ,分别用来实现双向连接的server 端和client 端. -- ...

  5. [Python 网络编程] TCP编程/群聊服务端 (二)

    群聊服务端 需求分析: 1. 群聊服务端需支持启动和停止(清理资源); 2. 可以接收客户端的连接; 接收客户端发来的数据 3. 可以将每条信息分发到所有客户端 1) 先搭架子: #TCP Serve ...

  6. Java 网络编程 -- 基于TCP 实现聊天室 群聊 私聊

    分析: 聊天室需要多个客户端和一个服务端. 服务端负责转发消息. 客户端可以发送消息.接收消息. 消息分类: 群聊消息:发送除自己外所有人 私聊消息:只发送@的人 系统消息:根据情况分只发送个人和其他 ...

  7. websocket实现群聊和单聊(转)

    昨日内容回顾 1.Flask路由 1.endpoint="user" # 反向url地址 2.url_address = url_for("user") 3.m ...

  8. JAVA 网络编程 - 实现 群聊 程序

    在实现 这个 程序之前, 我们 需要 了解 一些 关于 Java 网络 编程 的 知识. 基本 的 网络知识: 网络模型 OSI (Open System Interconnection 开放系统互连 ...

  9. java基于socket的网络通信,实现一个服务端多个客户端的群聊,传输文件功能,界面使用Swing

    最近在复习java的io流及网络编程.但复习写那些样板程序总是乏味的.便准备写个项目来巩固.想来想去还是聊天项目比较好玩.如果日后完成的比较好自己也可以用(哈哈哈).并且自己后面也要继续巩固java多 ...

随机推荐

  1. Aizu - 2555 Everlasting Zero 模拟

    Aizu - 2555 Everlasting Zero 题意:学习技能,每个技能有不同的要求,问能否学习全部特殊技能 思路:枚举每两个技能,得到他们的先后学习关系,如果两个都不能先学的话就是No了, ...

  2. 《TensorFlow学习指南深度学习系统构建详解》英文PDF+源代码+部分中文PDF

    主要介绍如何使用 TensorFlow 框架进行深度学习系统的构建.涉及卷积神经网络.循环神经网络等核心的技术,并介绍了用于图像数据和文本序列数据的模型.给出了分布式深度学习系统在TensorFlow ...

  3. 将yyyyMMdd格式的字符串转成日期DateTime格式

    1.DateTime dt= DateTime.ParseExact("20110720", "yyyyMMdd", Thread.CurrentThread. ...

  4. JS中的onload与jQuery中的ready差别

    jQuery的运行机制(onload与ready的差别) 结论得出前自行測试: 为了測试是否真如所说的那样,所以在页面插入了20000张照片,照片数量少得不出什么结论,所以改用console.log( ...

  5. int long long 的取值范围

    unsigned   int   0-4294967295   //整型的每一种都有无符号(unsigned)和有符号(signed)两种类型(float和double总是带符号的),在默认情况下声明 ...

  6. uva103 - Stacking Boxes(DAG)

    题目:uva103 - Stacking Boxes(DAG) 题目大意:给出N个boxes, 而且给出这些箱子的维度.要求找一个最长的序列.可以使得以下的箱子一定可以有个维度序列大于上面的那个箱子的 ...

  7. 42.管道,cmd执行指令写到管道中

    #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <stri ...

  8. WinRAR 5.21 去弹窗 疑惑

    WinRAR 突然就有弹窗广告了 ,找了个方法,重新写一下安装目录下的 rarreg.key,确实有效果但是重写的和之前的完全一样啊,至少在文本中完全一样,怎么回事. 下面附上两个文件, 1.key ...

  9. Spark Tachyon的命令行使用

    Tachyon命令行使用 Tachyon接口说明 接口操作示例 copyFromLocal copyToLocal ls和lsr count cat mkdir.rm.rmr和touch pin和un ...

  10. jQuery简单tab按钮切换

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...