TCP实现局域网通信

TCP实现局域网通信

TCP客户端通信步骤:
1:创建套接字 sockfd = socket(AF_INET ,SOCK_STREAM ,0);
2:填写服务器结构体信息

 struct sockaddr_in serveraddr;
socklen_t addrlen = sizeof(serveraddr);
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));

其中服务器信息结构体要用sockaddr_in创建
3:发送客户端连接请求

connect(sockfd, (struct sockaddr *)&serveraddr,addrlen);

注意服务器信息结构体要进行强制类型转换
4:进行通信

recv(sockfd, buf1, 128, 0);
send(sockfd, buf, 128, 0);
注意send和recv可以设置阻塞和非阻塞 recv默认阻塞

其中可以通过创建进程和线程实现接收和发送
5:关闭套接字
TCP服务器通信步骤:
1:创建套接字

sockfd = socket(AF_INET, SOCK_STREAM, 0)

2:将套接字和服务器信息结构体绑定

struct sockaddr_in serveraddr, clientaddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
bind(sockfd, (struct sockaddr *)&serveraddr, addrlen)

3:将套接字设置为监听状态

listen(sockfd, 5)

4:阻塞等待客户端连接请求

acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)

5:进行通信
6:关闭套接字
关闭监听套接字导致服务器无法建立新连接,但不影响已建立连接
关闭accept返回的套接字代表该套接字的连接关闭,不影响服务器监听
实现TCP并发服务器
客户端代码:client_Ancy.c

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <netinet/in.h> //sockaddr_in
#include <arpa/inet.h> //htons inet_addr

z
	char buf1[128] = "";
        pthread_t thread;
	int sockfd;
	char ip[] = "180.201.00.00";
	char port[] = "8080";
void thread_do(){
while(1){

	fgets(buf,128,stdin);
	buf[strlen(buf) - 1] = '\0';
	
	send(sockfd, buf, 128, 0);

}
}
int main(int argc, char const *argv[])
{
	if (argc<3){
        printf("Usage: %s [ip] [port]\n", argv[0]);
        exit(1);
	}

	sockfd = socket(AF_INET ,SOCK_STREAM ,0);
	
	
         struct sockaddr_in serveraddr;
        socklen_t addrlen = sizeof(serveraddr);
        
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
        serveraddr.sin_port = htons(atoi(argv[2]));
        //serveraddr.sin_addr.s_addr = inet_addr(ip);
        //serveraddr.sin_port = htons(atoi(port));

	
	connect(sockfd, (struct sockaddr *)&serveraddr,addrlen);
	
	pthread_create(&thread, NULL, (void *)&thread_do,NULL);//此时可以通过把thread_do设置为指针函数,即定义时void * thread_do()参数可以写thread_do
	
while(1){
	memset(buf1,0,128);
	recv(sockfd, buf1, 128, 0);
	printf("recv:%s\n",buf1);
	}
	close(sockfd);

}

多进程实现服务器代码:server_Ancy.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <signal.h>

//使用多进程实现TCP并发服务器

#define N 128
#define ERR_LOG(errmsg) do{\
                            perror(errmsg);\
                            exit(1);\
                        }while(0)

void handler(int sig)
{
    wait(NULL);
}

int main(int argc, char const *argv[])
{
    if(argc < 3)
    {
        fprintf(stderr, "Usage: %s <server_ip> <server_port>\n", argv[0]);
        exit(1);
    }    

    int sockfd, acceptfd;
    struct sockaddr_in serveraddr, clientaddr;
    socklen_t addrlen = sizeof(serveraddr);

    //第一步:创建套接字
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        ERR_LOG("fail to socket");
    }

    //将套接字设置为允许重复使用本机地址或者为设置为端口复用
    int on = 1;
    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
    {
        ERR_LOG("fail to setsockopt");
    }

    //第二步:填充服务器网络信息结构体
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    //第三步:将套接字与服务器网络信息结构体绑定
    if(bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0)
    {
        ERR_LOG("fail to bind");
    }

    //第四步:将套接字设置为被动监听状态
    if(listen(sockfd, 5) < 0)
    {
        ERR_LOG("fail to listen");
    }

    //使用型号,异步的方式处理僵尸进程
    signal(SIGCHLD, handler);

    while(1)
    {
        //第五步:阻塞等待客户端的连接请求
        if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
        {
            ERR_LOG("fail to accept");
        }

        //打印客户端的信息
        printf("%s -- %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

        //使用fork函数创建子进程,父进程继续负责连接,子进程负责与客户端通信
        pid_t pid;
        if((pid = fork()) < 0)
        {
            ERR_LOG("fail to fork");
        }
        else if(pid > 0) //父进程负责执行accept,所以if语句结束后继续在accept函数的位置阻塞
        {
        }
        else //子进程负责跟指定的客户端通信
        {
            char buf[N] = "";
            ssize_t bytes;
            while (1)
            {
                if((bytes = recv(acceptfd, buf, N, 0)) < 0)
                {
                    ERR_LOG("fail to recv");
                }
                else if(bytes == 0)
                {
                    printf("The client quited\n");
                    exit(0);
                }

                if(strncmp(buf, "quit", 4) == 0)
                {
                    exit(0);
                }

                printf("from client: %s\n", buf);

                strcat(buf, " ^_^");
                if(send(acceptfd, buf, N, 0) < 0)
                {
                    ERR_LOG("fail to send");
                }
            }
        }
    }

    return 0;
}

多线程实现服务器代码:server_Ancy.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>

#define N 128
#define ERR_LOG(errmsg) do{\
                            perror(errmsg);\
                            exit(1);\
                        }while(0)

typedef struct{
    struct sockaddr_in addr;
    int acceptfd;
}MSG;

void *pthread_fun(void *arg)
{
    char buf[N] = "";
    ssize_t bytes;
    MSG msg = *(MSG *)arg;
    while (1)
    {
        if((bytes = recv(msg.acceptfd, buf, N, 0)) < 0)
        {
            ERR_LOG("fail to recv");
        }
        else if(bytes == 0)
        {
            printf("The client quited\n");
            pthread_exit(NULL);
        }

        if(strncmp(buf, "quit", 4) == 0)
        {
            printf("The client quited\n");
            pthread_exit(NULL);
        }

        printf("[%s - %d]: %s\n", inet_ntoa(msg.addr.sin_addr), ntohs(msg.addr.sin_port), buf);

        strcat(buf, " ^_^");
        if(send(msg.acceptfd, buf, N, 0) < 0)
        {
            ERR_LOG("fail to send");
        }
    }
}

int main(int argc, char const *argv[])
{
    if(argc < 3)
    {
        fprintf(stderr, "Usage: %s <server_ip> <server_port>\n", argv[0]);
        exit(1);
    }    

    int sockfd, acceptfd;
    struct sockaddr_in serveraddr, clientaddr;
    socklen_t addrlen = sizeof(serveraddr);

    //第一步:创建套接字
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        ERR_LOG("fail to socket");
    }

    //将套接字设置为允许重复使用本机地址或者为设置为端口复用
    int on = 1;
    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
    {
        ERR_LOG("fail to setsockopt");
    }

    //第二步:填充服务器网络信息结构体
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    //第三步:将套接字与服务器网络信息结构体绑定
    if(bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0)
    {
        ERR_LOG("fail to bind");
    }

    //第四步:将套接字设置为被动监听状态
    if(listen(sockfd, 5) < 0)
    {
        ERR_LOG("fail to listen");
    }

    while(1)
    {
        //第五步:阻塞等待客户端的连接请求
        if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
        {
            ERR_LOG("fail to accept");
        }

        //打印客户端的信息
        //printf("%s -- %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

        //创建子线程与客户端进行通信
        MSG msg;
        msg.addr = clientaddr;
        msg.acceptfd = acceptfd;
        pthread_t thread;
        if(pthread_create(&thread, NULL, pthread_fun, &msg) != 0)
        {
            ERR_LOG("fail to pthread_create");
        }
        pthread_detach(thread);
    }

    return 0;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: TCP通信局域网环境下丢包可能有以下几个原因: 1. 网络拥塞:如果局域网中的网络流量过大,可能导致数据包丢失。可以通过增加网络带宽或者优化网络拓扑结构来缓解拥塞问题。 2. 网络延迟:如果数据包在传输时遇到网络延迟,可能导致数据包丢失。可以优化网络设备的配置来缩短网络延迟。 3. 硬件问题:局域网中的网络设备(如交换机、路由器等)可能存在硬件问题,导致数据包丢失。可以检查设备是否正常工作,或者更换设备。 4. 程序问题:程序本身可能存在漏洞或者逻辑错误,导致数据包丢失。可以通过检查程序代码来排查问题。 针对丢包问题,可以通过以下方式进行优化: 1. 使用可靠的传输协议:TCP是一种可靠的传输协议,可以保证数据传输的可靠性和完整性。可以通过使用TCP协议来避免丢包问题。 2. 增加重传机制:在通信过程中,可以增加重传机制,当发现数据包丢失时,及时重传数据包,保证数据的完整性。 3. 优化程序设计:在程序设计过程中,可以考虑数据包大小、发送频率等因素,避免数据包丢失。同时,可以增加数据校验机制,保证数据的完整性。 ### 回答2: Qt是一个跨平台的应用程序开发框架,其中包含了TCP通信的功能,可以用于在局域网内进行数据传输。丢包问题是指在通信过程中,部分数据包无法正常传输到目标主机的现象。 局域网丢包问题的解决可以从以下几个方面来考虑: 1. 检查网络环境:首先,需要检查局域网的网络环境是否稳定。可能是由于网络延迟、带宽限制或者网络拥堵等原因导致数据包丢失。可以尝试进行网络优化,例如调整网络带宽、增加网络缓冲区大小等方式来改善网络环境。 2. 优化代码逻辑:在进行TCP通信时,需要合理地编写代码逻辑,确保数据包的稳定传输。可以通过添加重传机制、数据校验等方式来提高通信的可靠性。同时,也要合理地设置缓冲区大小,防止数据包溢出或者缓存积压导致丢包。 3. 异常处理机制:考虑到网络通信的不确定性,需要在代码中添加异常处理机制,及时捕获并处理异常情况,避免程序崩溃或者数据丢失。可以使用Qt提供的信号槽机制来实现异常处理,例如捕获网络错误信号并进行相应处理。 4. 数据分包处理:如果遇到较大的数据传输,可以将数据分包发送,以减少数据包的丢失概率。可以将大块数据按照固定大小进行切割,并添加相关的标记进行拼接。在接收端接收到所有数据包后,再进行拼装。 总结来说,局域网丢包问题在Qt的TCP通信中是常见的,可以通过检查网络环境、优化代码逻辑、添加异常处理机制以及数据分包处理来解决。 ### 回答3: Qt是一种跨平台的C++应用程序开发框架,它提供了丰富的库和工具,方便开发人员进行图形界面和网络通信实现。 在使用Qt进行tcp通信时,有时候会遇到局域网丢包的问题。丢包通常是由网络环境不稳定、网络拥塞或其他因素引起的。 为了解决局域网丢包问题,可以尝试以下方法: 1. 检查网络环境:确保局域网连接稳定,并且没有其他设备在占用过多带宽。 2. 设置超时时间:在Qt中,可以为tcp连接设置超时时间,如果在指定时间内没有收到响应,可以进行重试或其他处理。 3. 使用可靠的传输协议:如果对数据的可靠性要求较高,可以考虑使用可靠的传输协议,如TCP协议。 4. 重新建立连接:如果发现连接丢失或者数据丢失,可以尝试重新建立连接,或者通过心跳包等机制检测连接状态。 5. 错误处理和重试机制:在代码中添加适当的错误处理和重试机制,当发现丢包时,可以重试发送丢失的数据。 6. 数据校验和重传:在发送数据时可以附加校验和,接收端在接收数据后校验数据的完整性,并进行重传,以确保数据的准确传输。 总之,解决Qt tcp通信局域网丢包问题需要综合考虑网络环境、传输协议、错误处理和重试机制等多个方面。通过合理的设置和处理,可以提高局域网通信的可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值