c - window C : TCP Socket send&recv at the same time

标签 c multithreading sockets tcp winsock

我正在尝试通过 TCP 套接字在 Windows 上的服务器和客户端之间进行双向通信。我尝试过使用线程,但它不起作用,我不知道为什么。

如果我尝试将其放入 while 循环中,它会等待用户输入某些内容(因为 fgets()),然后再打印下一条消息。

while(1) {
        bzero(message, 2000);
        if (recv(sock, message, 2000, 0) < 0) {
            printf("Connection lost!\n");
            getch();
        }
        else {
            strcat(message, "\0");
            fprintf(stdout, "%s", message);
        };
        bzero(client, 2000);

        fgets(sednmesg, sizeof(sednmesg), stdin);
        strcat(client, sednmesg);
        strcat(client, "\0");
        send(sock, client, strlen(client), 0);
}

我对线程的灾难性尝试:

服务器.c:

#include <stdio.h>
#include <winsock.h>
#include <stdlib.h>
#include "stdafx.h"
#include <conio.h>
#include <io.h>

#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)  

#pragma comment(lib,"ws2_32.lib") //Winsock Library

char message[4040];

DWORD WINAPI thrd() {
    WSADATA wsa;
    SOCKET sock, newsock;
    int c;
    struct sockaddr_in server, client;
    char smesg[155];
    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        printf("Failed. Error Code : %d", WSAGetLastError());
        return 1;
    }

    printf("Initialised.\n");

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        printf("Could not create socket! Error: %d", WSAGetLastError());
        return 1;
    }
    //textcolor(2);
    printf("Socket Created!\n");

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(8989);

    //bind
    if (bind(sock, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) {
        printf("Bind failed! Error Code: %d", WSAGetLastError());
    }
    puts("Binded!");
    printf("\nNow Listening...\n");
    listen(sock, 1);
    //Accept!
    c = sizeof(struct sockaddr_in);
    newsock = accept(sock, (struct sockaddr *)&client, &c);
    if (newsock == INVALID_SOCKET) {
        printf("Couldn't Accept connection!");
    }

    printf("Accepted Connection!\n");
    u_long iMode = 1;
    ioctlsocket(newsock, FIONBIO, &iMode);
    Sleep(99);
    system("cls");
    printf("Writer Thread has been started!");
    //char *client_ip = inet_ntoa(client.sin_addr);
    //int client_port = ntohs(client.sin_port);
    while (1) {
        bzero(smesg, sizeof(smesg));
        fgets(smesg, sizeof(smesg), stdin);
        strcat(smesg, "\0");
        send(newsock, smesg, strlen(smesg), 0);
    }
}

int main()
{
    WSADATA wsa;
    FILE * fp;
    unsigned long on = 1;
    const char *file = "fout.txt";
    SOCKET sock, newsock;
    int c;
    struct sockaddr_in server, client;
    char smesg[155];
    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        printf("Failed. Error Code : %d", WSAGetLastError());
        return 1;
    }

    printf("Initialised.\n");

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        printf("Could not create socket! Error: %d", WSAGetLastError());
        return 1;
    }
    //textcolor(2);
    printf("Socket Created!\n");

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(3939);

    //bind
    if (bind(sock, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) {
        printf("Bind failed! Error Code: %d", WSAGetLastError());
    }
    puts("Binded!");
    printf("\nNow Listening...\n");
    listen(sock, 1);
    //Accept!
    c = sizeof(struct sockaddr_in);
    newsock = accept(sock, (struct sockaddr *)&client, &c);
    ioctlsocket(newsock, FIONBIO, &on);
    if (newsock == INVALID_SOCKET) {
        printf("Couldn't Accept connection!");
    }

    printf("Accepted Connection!\n");
        //char *client_ip = inet_ntoa(client.sin_addr);
        //int client_port = ntohs(client.sin_port);
    HANDLE thread = CreateThread(NULL, 0, thrd, NULL, 0, NULL);
    fp = fopen(file, "r+");
        while (1) {
            /*
            bzero(smesg, sizeof(smesg));
            printf("Command: ");
            fgets(smesg, 155, stdin);
            strcat(smesg, "\0");
            send(newsock, smesg, strlen(smesg), 0);
            */
            bzero(message, sizeof(message));
            recv(newsock, message, 2000, 0);
            fprintf(stdout, "%s", message);
            fprintf(fp, "%s", message);
        }
        fclose(fp);
    return 0;
}

客户端.c:

#include <stdio.h>
#include <winsock.h>
#include <stdlib.h>
#include "stdafx.h"
#include <conio.h>

#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)  

#pragma comment(lib,"ws2_32.lib") //Winsock Library

DWORD WINAPI thrd() {
    char client[2050] = "Client: ";
    WSADATA wsa;
    SOCKET sock;
    struct sockaddr_in server;
    char sednmesg[2000];
    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        printf("Failed. Error Code : %d", WSAGetLastError());
        getch();
        return 1;
    }

    printf("Initialised.\n");


    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        printf("Could not create socket! Error: %d", WSAGetLastError());
        getch();
        return 1;
    }
    //textcolor(2);
    printf("Socket Created!\n");
    //ioctlsocket(sock, FIONBIO, &on);
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_family = AF_INET;
    server.sin_port = htons(8989);

    //Connect
    if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
        puts("Connect Error");
        getch();
        return 1;
    }
    puts("Connected\n");
    // If iMode!=0, non-blocking mode is enabled.
    u_long iMode = 1;
    ioctlsocket(sock, FIONBIO, &iMode);
    Sleep(99);
    system("cls");
    printf("Writer Thread has been started!");
    //We'll be running this one on port 8989 if this doesn't work!
    while (1) {
        bzero(client, 2000);
        fgets(sednmesg, sizeof(sednmesg), stdin);
        strcat(client, sednmesg);
        strcat(client, "\0");
        send(sock, client, strlen(client), 0);
    }
}

int main(int argc, char *argv[])
{
    char *msg = "a";
    char client[2050] = "Client: ";
    unsigned long on = 1;
    int reader;
    WSADATA wsa;
    int sent = 0;
    SOCKET sock;
    struct sockaddr_in server;
    char message[2000];
    char sednmesg[2000];
    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        printf("Failed. Error Code : %d", WSAGetLastError());
        getch();
        return 1;
    }

    printf("Initialised.\n");


    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        printf("Could not create socket! Error: %d", WSAGetLastError());
        getch();
        return 1;
    }
    //textcolor(2);
    printf("Socket Created!\n");
    //ioctlsocket(sock, FIONBIO, &on);
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_family = AF_INET;
    server.sin_port = htons(3939);

    //Connect
    if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
        puts("Connect Error");
        getch();
        return 1;
    }
    puts("Connected\n");
    // If iMode!=0, non-blocking mode is enabled.
    u_long iMode = 1;
    ioctlsocket(sock, FIONBIO, &iMode);
    //Creating writer thread.
    HANDLE thread = CreateThread(NULL, 0, thrd, NULL, 0, NULL);
    while (1) {
        bzero(message, 2000);
        if (recv(sock, message, 2000, 0) < 0) {
            printf("Connection lost!\n");
            getch();
        }
        else {
            strcat(message, "\0");
            fprintf(stdout, "%s", message);
        };
        //bzero(client, 2000);
        /*
        fgets(sednmesg, sizeof(sednmesg), stdin);
        strcat(client, sednmesg);
        strcat(client, "\0");
        send(sock, client, strlen(client), 0);
        */
    }
    return 0;
}

最佳答案

您不需要打开/连接 2 个单独的监听端口来实现双向通信。 TCP 是双向的,您只需要一个连接。但是,您在两端都启用了非阻塞套接字 I/O,但实际上并未正确使用非阻塞 I/O。特别是,您根本没有处理 WSAEWOULDBLOCK 错误代码,该错误代码在没有数据可供读取时由 recv() 报告,并由 send 报告()当接收方有太多数据需要读取并且还无法接收新数据时。

如果你想使用线程,那么使用单独的线程来读取和发送,并且完全忘记非阻塞 I/O。但请确保您正确定义了线程(您的线程过程缺少必需的输入参数!)。

尝试更多类似这样的事情:

服务器.c:

#include "stdafx.h"
#include <stdio.h>
#include <winsock.h>
#include <stdlib.h>
#include <conio.h>

#pragma comment(lib,"ws2_32.lib") //Winsock Library

DWORD WINAPI sendThrd(LPVOID lpParam)
{
    SOCKET sock = * (SOCKET*) lpParam;
    char smesg[155], *pdata;
    int len, ret;

    do
    {
        if (!fgets(smesg, sizeof(smesg), stdin))
            break;

        len = strlen(smesg);
        pdata = smesg;

        while (len > 0)
        {
            ret = send(sock, pdata, len, 0);
            if (ret == SOCKET_ERROR)
            {
                printf("Send failed. Error: %d", WSAGetLastError());
                break;
            }
            pdata += ret;
            len -= ret;
        }
    }
    while (true);

    shutdown(sock, SD_SEND);
    return 0;
}

DWORD WINAPI recvThrd(LPVOID lpParam)
{
    SOCKET sock = * (SOCKET*) lpParam;
    char smesg[256];
    int ret;

    FILE *fp = fopen("fout.txt", "w+");

    do
    {
        ret = recv(sock, smesg, sizeof(smesg), 0);
        if (ret <= 0)
        {
            if (ret == 0)
                printf("Client disconnected\n");
            else
                printf("Connection lost! Error: %d\n", WSAGetLastError());
            break;
        }

        printf("%.*s", ret, smesg);

        if (fp)
            fprintf(fp, "%.*s", ret, smesg);        
    }
    while (true);

    if (fp)
        fclose(fp);

    shutdown(sock, SD_RECEIVE);
    return 0;
}

int main()
{
    WSADATA wsa;
    SOCKET sock, newsock;
    int c;
    struct sockaddr_in server;

    printf("Initializing Winsock...\n");
    int ret = WSAStartup(MAKEWORD(2, 2), &wsa);
    if (ret != 0)
    {
        printf("Initialization Failed. Error: %d", ret);
        return 1;
    }
    printf("Initialized.\n");

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        printf("Could not create socket! Error: %d\n", WSAGetLastError());
        return 1;
    }
    //textcolor(2);
    printf("Socket Created!\n");

    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(3939);

    //bind
    if (bind(sock, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) {
        printf("Bind failed! Error: %d\n", WSAGetLastError());
        closesocket(sock);
        return 1;
    }
    printf("Binded!\n");

    // listen
    if (listen(sock, 1) == SOCKET_ERROR) {
        printf("Listen failed! Error: %d\n", WSAGetLastError());
        closesocket(sock);
        return 1;
    }
    printf("Now Listening...\n");

    //Accept!
    c = sizeof(client);
    newsock = accept(sock, (struct sockaddr *)&client, &c);
    if (newsock == INVALID_SOCKET) {
        printf("Couldn't Accept connection! Error: %d\n", WSAGetLastError());
        closesocket(sock);
        return 1;
    }

    //char *client_ip = inet_ntoa(client.sin_addr);
    //int client_port = ntohs(client.sin_port);
    printf("Accepted Connection!\n");

    printf("Starting Reader/Writer Threads...\n");
    HANDLE threads[2];
    threads[0] = CreateThread(NULL, 0, sendThrd, &newsock, 0, NULL);
    threads[1] = CreateThread(NULL, 0, recvThrd, &newsock, 0, NULL);

    WaitForMultipleObjects(2, threads, TRUE, INFINITE);

    CloseHandle(threads[0]);
    CloseHandle(threads[1]);

    closesocket(newsock);
    closesocket(sock);

    return 0;
}

客户端.c:

#include "stdafx.h"
#include <stdio.h>
#include <winsock.h>
#include <stdlib.h>
#include <conio.h>

#pragma comment(lib,"ws2_32.lib") //Winsock Library

DWORD WINAPI sendThrd(LPVOID lpParam)
{
    SOCKET sock = * (SOCKET*) lpParam;
    char smesg[155], *pdata;
    int len, ret;

    do
    {
        if (!fgets(smesg, sizeof(smesg), stdin))
            break;

        len = strlen(smesg);
        pdata = smesg;

        while (len > 0)
        {
            ret = send(sock, pdata, len, 0);
            if (ret == SOCKET_ERROR)
            {
                printf("Send failed. Error: %d\n", WSAGetLastError());
                break;
            }
            pdata += ret;
            len -= ret;
        }
    }
    while (true);

    shutdown(sock, SD_SEND);
    return 0;
}

DWORD WINAPI recvThrd(LPVOID lpParam)
{
    SOCKET sock = * (SOCKET*) lpParam;
    char smesg[256];
    int ret;

    do
    {
        ret = recv(sock, smesg, sizeof(smesg), 0);
        if (ret <= 0)
        {
            if (ret == 0)
                printf("Server disconnected\n");
            else
                printf("Connection lost! Error: %d\n", WSAGetLastError());
            break;
        }

        printf("%.*s", ret, smesg);
    }
    while (true);

    shutdown(sock, SD_RECEIVE);
    return 0;
}

int main(int argc, char *argv[])
{
    WSADATA wsa;
    SOCKET sock;
    struct sockaddr_in server;

    printf("Initializing Winsock...\n");
    int ret = WSAStartup(MAKEWORD(2, 2), &wsa);
    if (ret != 0)
    {
        printf("Initialization Failed. Error: %d", ret);
        return 1;
    }
    printf("Initialized.\n");

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET) {
        printf("Could not create socket! Error: %d", WSAGetLastError());
        getch();
        return 1;
    }
    //textcolor(2);
    printf("Socket Created!\n");

    memset(&server, 0, sizeof(server));
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_family = AF_INET;
    server.sin_port = htons(3939);

    //Connect
    if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) {
        printf("Connect failed! Error: %d", WSAGetLastError());
        closesocket(sock);
        getch();
        return 1;
    }
    printf("Connected\n");

    //Creating reader/writer threads.

    printf("Starting Reader/Writer Threads...\n");
    HANDLE threads[2];
    threads[0] = CreateThread(NULL, 0, sendThrd, &sock, 0, NULL);
    threads[1] = CreateThread(NULL, 0, recvThrd, &sock, 0, NULL);

    WaitForMultipleObjects(2, threads, TRUE, INFINITE);

    CloseHandle(threads[0]);
    CloseHandle(threads[1]);

    closesocket(sock);

    getch();
    return 0;
}

关于c - window C : TCP Socket send&recv at the same time,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43298052/

相关文章:

java - 调用某个线程的 start() 方法后,主线程是否立即获得控制权?

java - 如何在 JUnit 测试中的不同线程中启动 Main.main()

c - 结构体内部变量的地址计算

c - 如何释放 C 中的 n 字节内存?

c++ - 如何在驱动程序的 INF 文件中使用变量?

java - 如何在Java中不使用JMS从ActiveMQ读取消息

c - 如何在C中将IP4和IP6地址转换为长值?

c - 如何创建分布式阵列 MPI

python - 仅当不存在相同线程名称作为事件线程时才创建线程(Python)

java - 如何将从服务器收到的结果存储到文本文件中