WINDOWS C:TCP Socket同时发送& recv

时间:2017-04-08 17:13:21

标签: c multithreading sockets tcp winsock

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

如果我尝试将它放在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);
}

我对线程的灾难性尝试:

Server.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;
}

Client.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;
}

1 个答案:

答案 0 :(得分:0)

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

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

尝试更像这样的事情:

Server.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;
}

Client.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;
}